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