Home | History | Annotate | Download | only in widget
      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