blob: d77bc44c4ac3527dcc1453f9db64d89f84f9ca22 [file] [log] [blame]
/*
* 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));
}
}