/* * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.litho.animation; /** * Utility class for building animated transitions. */ public final class Animated { private Animated() { } /** * Creates an AnimationBinding which is a sequence of other animation bindings (i.e. each executes * after the previous one has finished). */ public static AnimationBinding sequence(AnimationForVarArgs... bindings) { return new SequenceBinding(createAnimationBindingsFromMixed(bindings)); } /** * Creates an AnimationBinding which is a collection of other animation bindings starting at the * same time and executing in parallel. */ public static AnimationBinding parallel(AnimationForVarArgs... bindings) { return new ParallelBinding(0, createAnimationBindingsFromMixed(bindings)); } /** * Creates an AnimationBinding which is a collection of other animation bindings starting on a * stagger and executing in parallel. */ public static AnimationBinding stagger(int staggerMs, AnimationForVarArgs... bindings) { return new ParallelBinding(staggerMs, createAnimationBindingsFromMixed(bindings)); } /** * Build a spring animation. */ public static SpringBuilder spring() { return new SpringBuilder(); } /** * Build a spring animation. */ public static TimingBuilder timing() { return new TimingBuilder(); } /** * Build a Bezier curve transition. */ public static BezierBuilder bezier() { return new BezierBuilder(); } private static AnimationBinding[] createAnimationBindingsFromMixed( AnimationForVarArgs[] bindings) { AnimationBinding[] animationBindings = new AnimationBinding[bindings.length]; for (int i = 0; i < bindings.length; i++) { if (bindings[i] instanceof AnimationBinding) { animationBindings[i] = (AnimationBinding) bindings[i]; } else if (bindings[i] instanceof AnimationBuilder) { animationBindings[i] = ((AnimationBuilder) bindings[i]).build(); } else { throw new RuntimeException("Got unexpected object in animation var args: " + bindings[i]); } } return animationBindings; } /** * Class that can create an AnimationBinding. */ public interface AnimationBuilder extends AnimationForVarArgs { AnimationBinding build(); } public static abstract class AbstractBuilder { private ComponentProperty mProperty; public AppearingDimensionComponentProperty.TransitionBuilder animate( AppearingDimensionComponentProperty property) { mProperty = property; return new AppearingDimensionComponentProperty.TransitionBuilder(this); } public AppearingFloatComponentProperty.TransitionBuilder animate( AppearingFloatComponentProperty property) { mProperty = property; return new AppearingFloatComponentProperty.TransitionBuilder(this); } public FloatComponentProperty.TransitionBuilder animate(FloatComponentProperty property) { mProperty = property; return new FloatComponentProperty.TransitionBuilder(this); } public DimensionComponentProperty.TransitionBuilder animate( DimensionComponentProperty property) { mProperty = property; return new DimensionComponentProperty.TransitionBuilder(this); } public DisappearingDimensionComponentProperty.TransitionBuilder animate( DisappearingDimensionComponentProperty property) { mProperty = property; return new DisappearingDimensionComponentProperty.TransitionBuilder(this); } public DisappearingFloatComponentProperty.TransitionBuilder animate( DisappearingFloatComponentProperty property) { mProperty = property; return new DisappearingFloatComponentProperty.TransitionBuilder(this); } final TransitionAnimationBinding buildForAppear(RuntimeValue fromValue) { final TransitionAnimationBinding transition = buildTransition(mProperty); transition.addAppearFromValue(mProperty, fromValue); return transition; } final TransitionAnimationBinding buildForChange() { return buildTransition(mProperty); } final TransitionAnimationBinding buildForDisappear(RuntimeValue toValue) { final TransitionAnimationBinding transition = buildTransition(mProperty); transition.addDisappearToValue(mProperty, toValue); return transition; } abstract TransitionAnimationBinding buildTransition(ComponentProperty property); } public static abstract class AbstractPointBuilder { private PositionComponentProperty mProperty; public AppearingPositionComponentProperty.TransitionBuilder animate( AppearingPositionComponentProperty property) { mProperty = property; return new AppearingPositionComponentProperty.TransitionBuilder(this); } public PositionComponentProperty.TransitionBuilder animate(PositionComponentProperty property) { mProperty = property; return new PositionComponentProperty.TransitionBuilder(this); } public DisappearingPositionComponentProperty.TransitionBuilder animate( DisappearingPositionComponentProperty property) { mProperty = property; return new DisappearingPositionComponentProperty.TransitionBuilder(this); } final TransitionAnimationBinding buildForAppear(RuntimeValue fromX, RuntimeValue fromY) { final TransitionAnimationBinding transition = buildTransition(mProperty); transition.addAppearFromValue(mProperty.getXProperty(), fromX); transition.addAppearFromValue(mProperty.getYProperty(), fromY); return transition; } final TransitionAnimationBinding buildForChange() { return buildTransition(mProperty); } final TransitionAnimationBinding buildForDisappear(RuntimeValue toX, RuntimeValue toY) { final TransitionAnimationBinding transition = buildTransition(mProperty); transition.addDisappearToValue(mProperty.getXProperty(), toX); transition.addDisappearToValue(mProperty.getYProperty(), toY); return transition; } abstract TransitionAnimationBinding buildTransition(PositionComponentProperty property); } public static class SpringBuilder extends AbstractBuilder { @Override TransitionAnimationBinding buildTransition(ComponentProperty property) { return new SpringTransition(property); } } public static class TimingBuilder extends AbstractBuilder { private int mDurationMs = 300; public TimingBuilder durationMs(int durationMs) { mDurationMs = durationMs; return this; } @Override TransitionAnimationBinding buildTransition(ComponentProperty property) { return new TimingTransition(mDurationMs, property); } } public static class BezierBuilder extends AbstractPointBuilder { private float mControlPointX = 0; private float mControlPointY = 1; /** * Configures the control point of this quadratic bezier curve, determining the shape of the * curve. Because we don't know the start/end positions beforehand, the control point is defined * in terms of the distance between the start and end points of this animation. It is NOT in * terms of pixels or dp. * * Specifically, controlPointX=0 will give the control point the x position of initial position * of the curve. controlPointX=1 will give the control point the x position of the end of the * curve. controlPointX=.5 will give it the x position midway between the start and end x * positions. Increasing the value beyond 1 or below 0 will move the control point beyond the * end x position or before the start x position, respectively, while values between 0 and 1 * will place the point in between the start and end x positions. * * All of the above also applies to the controlPointY value as well. * * For good looking curves, you want to make sure controlPointX != controlPointY (or else the * curve won't curve since it lies on the straight line between the start and end points). */ public BezierBuilder controlPoint(float controlPointX, float controlPointY) { mControlPointX = controlPointX; mControlPointY = controlPointY; return this; } @Override TransitionAnimationBinding buildTransition(PositionComponentProperty property) { return new BezierTransition( property.getXProperty(), property.getYProperty(), mControlPointX, mControlPointY); } } }