1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.leanback.widget; 18 19 import android.animation.PropertyValuesHolder; 20 import android.content.Context; 21 import android.graphics.Color; 22 import android.graphics.drawable.ColorDrawable; 23 import android.graphics.drawable.Drawable; 24 import android.util.TypedValue; 25 26 import androidx.annotation.ColorInt; 27 import androidx.annotation.RestrictTo; 28 import androidx.leanback.R; 29 import androidx.leanback.graphics.CompositeDrawable; 30 import androidx.leanback.graphics.FitWidthBitmapDrawable; 31 32 /** 33 * Helper class responsible for wiring in parallax effect in 34 * {@link androidx.leanback.app.DetailsFragment}. The default effect will render 35 * a drawable like the following two parts, cover drawable above DetailsOverviewRow and solid 36 * color below DetailsOverviewRow. 37 * <pre> 38 * *************************** 39 * * Cover Drawable * 40 * *************************** 41 * * DetailsOverviewRow * 42 * * * 43 * *************************** 44 * * Bottom Drawable * 45 * * (Solid Color) * 46 * * Related * 47 * * Content * 48 * *************************** 49 * </pre> 50 * <ul> 51 * <li> 52 * Call {@link #DetailsParallaxDrawable(Context, DetailsParallax)} to create DetailsParallaxDrawable 53 * using {@link FitWidthBitmapDrawable} for cover drawable. 54 * </li> 55 * </ul> 56 * <li> 57 * In case the solid color is not set, it will use defaultBrandColorDark from LeanbackTheme. 58 * </li> 59 * @hide 60 */ 61 @RestrictTo(RestrictTo.Scope.LIBRARY) 62 public class DetailsParallaxDrawable extends CompositeDrawable { 63 private Drawable mBottomDrawable; 64 65 /** 66 * Creates a DetailsParallaxDrawable using a cover drawable. 67 * @param context Context to get resource values. 68 * @param parallax DetailsParallax to add background parallax effect. 69 * @param coverDrawable Cover drawable at top 70 * @param coverDrawableParallaxTarget Define a ParallaxTarget that would be performed on cover 71 * Drawable. e.g. To change "verticalOffset" of cover 72 * Drawable from 0 to 120 pixels above screen, uses: 73 * new ParallaxTarget.PropertyValuesHolderTarget( 74 * coverDrawable, 75 * PropertyValuesHolder.ofInt("verticalOffset", 0, -120)) 76 */ 77 public DetailsParallaxDrawable(Context context, DetailsParallax parallax, 78 Drawable coverDrawable, 79 ParallaxTarget coverDrawableParallaxTarget) { 80 init(context, parallax, coverDrawable, new ColorDrawable(), coverDrawableParallaxTarget); 81 } 82 83 /** 84 * Creates a DetailsParallaxDrawable using a cover drawable and bottom drawable. 85 * @param context Context to get resource values. 86 * @param parallax DetailsParallax to add background parallax effect. 87 * @param coverDrawable Cover drawable at top 88 * @param bottomDrawable Bottom drawable, when null it will create a default ColorDrawable. 89 * @param coverDrawableParallaxTarget Define a ParallaxTarget that would be performed on cover 90 * Drawable. e.g. To change "verticalOffset" of cover 91 * Drawable from 0 to 120 pixels above screen, uses: 92 * new ParallaxTarget.PropertyValuesHolderTarget( 93 * coverDrawable, 94 * PropertyValuesHolder.ofInt("verticalOffset", 0, -120)) 95 */ 96 public DetailsParallaxDrawable(Context context, DetailsParallax parallax, 97 Drawable coverDrawable, Drawable bottomDrawable, 98 ParallaxTarget coverDrawableParallaxTarget) { 99 100 init(context, parallax, coverDrawable, bottomDrawable, coverDrawableParallaxTarget); 101 } 102 103 /** 104 * Creates DetailsParallaxDrawable using {@link FitWidthBitmapDrawable} for cover drawable. 105 * @param context Context to get resource values. 106 * @param parallax DetailsParallax to add background parallax effect. 107 */ 108 public DetailsParallaxDrawable(Context context, DetailsParallax parallax) { 109 int verticalMovementMax = -context.getResources().getDimensionPixelSize( 110 R.dimen.lb_details_cover_drawable_parallax_movement); 111 Drawable coverDrawable = new FitWidthBitmapDrawable(); 112 ParallaxTarget coverDrawableParallaxTarget = new ParallaxTarget.PropertyValuesHolderTarget( 113 coverDrawable, PropertyValuesHolder.ofInt("verticalOffset", 0, 114 verticalMovementMax)); 115 init(context, parallax, coverDrawable, new ColorDrawable(), coverDrawableParallaxTarget); 116 } 117 118 void init(Context context, DetailsParallax parallax, 119 Drawable coverDrawable, Drawable bottomDrawable, 120 ParallaxTarget coverDrawableParallaxTarget) { 121 if (bottomDrawable instanceof ColorDrawable) { 122 ColorDrawable colorDrawable = ((ColorDrawable) bottomDrawable); 123 if (colorDrawable.getColor() == Color.TRANSPARENT) { 124 colorDrawable.setColor(getDefaultBackgroundColor(context)); 125 } 126 } 127 addChildDrawable(coverDrawable); 128 addChildDrawable(mBottomDrawable = bottomDrawable); 129 connect(context, parallax, coverDrawableParallaxTarget); 130 } 131 132 private static int getDefaultBackgroundColor(Context context) { 133 TypedValue outValue = new TypedValue(); 134 if (context.getTheme().resolveAttribute(R.attr.defaultBrandColorDark, outValue, true)) { 135 return context.getResources().getColor(outValue.resourceId); 136 } 137 return context.getResources().getColor(R.color.lb_default_brand_color_dark); 138 } 139 140 /** 141 * @return First child which is cover drawable appearing at top. 142 */ 143 public Drawable getCoverDrawable() { 144 return getChildAt(0).getDrawable(); 145 } 146 147 /** 148 * @return Second child which is ColorDrawable by default. 149 */ 150 public Drawable getBottomDrawable() { 151 return mBottomDrawable; 152 } 153 154 /** 155 * Changes the solid background color of the related content section. 156 */ 157 public void setSolidColor(@ColorInt int color) { 158 ((ColorDrawable) mBottomDrawable).setColor(color); 159 } 160 161 /** 162 * @return Returns the solid background color of the related content section. 163 */ 164 public @ColorInt int getSolidColor() { 165 return ((ColorDrawable) mBottomDrawable).getColor(); 166 } 167 168 /** 169 * Connects DetailsParallaxDrawable to DetailsParallax object. 170 * @param parallax The DetailsParallax object to add ParallaxEffects for the drawable. 171 */ 172 void connect(Context context, DetailsParallax parallax, 173 ParallaxTarget coverDrawableParallaxTarget) { 174 175 Parallax.IntProperty frameTop = parallax.getOverviewRowTop(); 176 Parallax.IntProperty frameBottom = parallax.getOverviewRowBottom(); 177 178 final int fromValue = context.getResources() 179 .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_actions); 180 final int toValue = context.getResources() 181 .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_description); 182 parallax.addEffect(frameTop.atAbsolute(fromValue), frameTop.atAbsolute(toValue)) 183 .target(coverDrawableParallaxTarget); 184 185 // Add solid color parallax effect: 186 // When frameBottom moves from bottom of the screen to top of the screen, 187 // change solid ColorDrawable's top from bottom of screen to top of the screen. 188 parallax.addEffect(frameBottom.atMax(), frameBottom.atMin()) 189 .target(getChildAt(1), ChildDrawable.TOP_ABSOLUTE); 190 // Also when frameTop moves from bottom of screen to top of the screen, 191 // we are changing bottom of the bitmap from bottom of screen to top of screen. 192 parallax.addEffect(frameTop.atMax(), frameTop.atMin()) 193 .target(getChildAt(0), ChildDrawable.BOTTOM_ABSOLUTE); 194 } 195 196 } 197