| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.support.v17.leanback.widget; |
| |
| import android.animation.PropertyValuesHolder; |
| import android.content.Context; |
| import android.graphics.Color; |
| import android.graphics.drawable.ColorDrawable; |
| import android.graphics.drawable.Drawable; |
| import android.support.annotation.ColorInt; |
| import android.support.v17.leanback.R; |
| import android.support.v17.leanback.graphics.BoundsRule; |
| import android.support.v17.leanback.graphics.CompositeDrawable; |
| import android.support.v17.leanback.graphics.FitWidthBitmapDrawable; |
| import android.util.TypedValue; |
| |
| /** |
| * Helper class responsible for wiring in parallax effect in |
| * {@link android.support.v17.leanback.app.DetailsFragment}. The default effect will render |
| * a drawable like the following two parts, cover drawable above DetailsOverviewRow and solid |
| * color below DetailsOverviewRow. |
| * <pre> |
| * *************************** |
| * * Cover Drawable * |
| * *************************** |
| * * DetailsOverviewRow * |
| * * * |
| * *************************** |
| * * Bottom Drawable * |
| * * (Solid Color) * |
| * * Related * |
| * * Content * |
| * *************************** |
| * </pre> |
| * <ul> |
| * <li> |
| * Call {@link #DetailsParallaxDrawable(Context, DetailsParallax)} to create DetailsParallaxDrawable |
| * using {@link FitWidthBitmapDrawable} for cover drawable. |
| * </li> |
| * </ul> |
| * <li> |
| * In case the solid color is not set, it will use defaultBrandColorDark from LeanbackTheme. |
| * </li> |
| * @hide |
| */ |
| public class DetailsParallaxDrawable extends CompositeDrawable { |
| private Drawable mBottomDrawable; |
| |
| /** |
| * Creates a DetailsParallaxDrawable using a cover drawable. |
| * @param context Context to get resource values. |
| * @param parallax DetailsParallax to add background parallax effect. |
| * @param coverDrawable Cover drawable at top |
| * @param coverDrawableParallaxTarget Define a ParallaxTarget that would be performed on cover |
| * Drawable. e.g. To change "verticalOffset" of cover |
| * Drawable from 0 to 120 pixels above screen, uses: |
| * new ParallaxTarget.PropertyValuesHolderTarget( |
| * coverDrawable, |
| * PropertyValuesHolder.ofInt("verticalOffset", 0, -120)) |
| */ |
| public DetailsParallaxDrawable(Context context, DetailsParallax parallax, |
| Drawable coverDrawable, |
| ParallaxTarget coverDrawableParallaxTarget) { |
| init(context, parallax, coverDrawable, new ColorDrawable(), coverDrawableParallaxTarget); |
| } |
| |
| /** |
| * Creates a DetailsParallaxDrawable using a cover drawable and bottom drawable. |
| * @param context Context to get resource values. |
| * @param parallax DetailsParallax to add background parallax effect. |
| * @param coverDrawable Cover drawable at top |
| * @param bottomDrawable Bottom drawable, when null it will create a default ColorDrawable. |
| * @param coverDrawableParallaxTarget Define a ParallaxTarget that would be performed on cover |
| * Drawable. e.g. To change "verticalOffset" of cover |
| * Drawable from 0 to 120 pixels above screen, uses: |
| * new ParallaxTarget.PropertyValuesHolderTarget( |
| * coverDrawable, |
| * PropertyValuesHolder.ofInt("verticalOffset", 0, -120)) |
| */ |
| public DetailsParallaxDrawable(Context context, DetailsParallax parallax, |
| Drawable coverDrawable, Drawable bottomDrawable, |
| ParallaxTarget coverDrawableParallaxTarget) { |
| |
| init(context, parallax, coverDrawable, bottomDrawable, coverDrawableParallaxTarget); |
| } |
| |
| /** |
| * Creates DetailsParallaxDrawable using {@link FitWidthBitmapDrawable} for cover drawable. |
| * @param context Context to get resource values. |
| * @param parallax DetailsParallax to add background parallax effect. |
| */ |
| public DetailsParallaxDrawable(Context context, DetailsParallax parallax) { |
| int verticalMovementMax = -context.getResources().getDimensionPixelSize( |
| R.dimen.lb_details_cover_drawable_parallax_movement); |
| Drawable coverDrawable = new FitWidthBitmapDrawable(); |
| ParallaxTarget coverDrawableParallaxTarget = new ParallaxTarget.PropertyValuesHolderTarget( |
| coverDrawable, PropertyValuesHolder.ofInt("verticalOffset", 0, |
| verticalMovementMax)); |
| init(context, parallax, coverDrawable, new ColorDrawable(), coverDrawableParallaxTarget); |
| } |
| |
| void init(Context context, DetailsParallax parallax, |
| Drawable coverDrawable, Drawable bottomDrawable, |
| ParallaxTarget coverDrawableParallaxTarget) { |
| if (bottomDrawable instanceof ColorDrawable) { |
| ColorDrawable colorDrawable = ((ColorDrawable) bottomDrawable); |
| if (colorDrawable.getColor() == Color.TRANSPARENT) { |
| colorDrawable.setColor(getDefaultBackgroundColor(context)); |
| } |
| } |
| addChildDrawable(coverDrawable); |
| addChildDrawable(mBottomDrawable = bottomDrawable); |
| getChildAt(0).getBoundsRule().bottom = BoundsRule.inheritFromParent(1f); |
| getChildAt(1).getBoundsRule().top = BoundsRule.inheritFromParent(1f); |
| connect(context, parallax, coverDrawableParallaxTarget); |
| } |
| |
| private static int getDefaultBackgroundColor(Context context) { |
| TypedValue outValue = new TypedValue(); |
| if (context.getTheme().resolveAttribute(R.attr.defaultBrandColorDark, outValue, true)) { |
| return context.getResources().getColor(outValue.resourceId); |
| } |
| return context.getResources().getColor(R.color.lb_default_brand_color_dark); |
| } |
| |
| /** |
| * @return First child which is cover drawable appearing at top. |
| */ |
| public Drawable getCoverDrawable() { |
| return getChildAt(0).getDrawable(); |
| } |
| |
| /** |
| * @return Second child which is ColorDrawable by default. |
| */ |
| public Drawable getBottomDrawable() { |
| return mBottomDrawable; |
| } |
| |
| /** |
| * Changes the solid background color of the related content section. |
| */ |
| public void setSolidColor(@ColorInt int color) { |
| ((ColorDrawable) mBottomDrawable).setColor(color); |
| } |
| |
| /** |
| * @return Returns the solid background color of the related content section. |
| */ |
| public @ColorInt int getSolidColor() { |
| return ((ColorDrawable) mBottomDrawable).getColor(); |
| } |
| |
| /** |
| * Connects DetailsParallaxDrawable to DetailsParallax object. |
| * @param parallax The DetailsParallax object to add ParallaxEffects for the drawable. |
| */ |
| void connect(Context context, DetailsParallax parallax, |
| ParallaxTarget coverDrawableParallaxTarget) { |
| |
| Parallax.IntProperty frameTop = parallax.getOverviewRowTop(); |
| Parallax.IntProperty frameBottom = parallax.getOverviewRowBottom(); |
| |
| final int fromValue = context.getResources() |
| .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_actions); |
| final int toValue = context.getResources() |
| .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_description); |
| parallax |
| .addEffect(frameTop.atAbsolute(fromValue), frameTop.atAbsolute(toValue)) |
| .target(coverDrawableParallaxTarget); |
| |
| // Add solid color parallax effect: |
| // When frameBottom moves from bottom of the screen to top of the screen, |
| // change solid ColorDrawable's top from bottom of screen to top of the screen. |
| parallax.addEffect(frameBottom.atFraction(1f), frameBottom.atFraction(0f)) |
| .target(getChildAt(1), |
| PropertyValuesHolder.ofFloat( |
| CompositeDrawable.ChildDrawable.TOP_FRACTION, 1f, 0f)); |
| // Also when frameTop moves from bottom of screen to top of the screen, |
| // we are changing bottom of the bitmap from bottom of screen to top of screen. |
| parallax.addEffect(frameTop.atFraction(1f), frameTop.atFraction(0f)) |
| .target(getChildAt(0), |
| PropertyValuesHolder.ofFloat( |
| CompositeDrawable.ChildDrawable.BOTTOM_FRACTION, 1f, 0f)); |
| } |
| |
| } |