Customizing Transitions
Litho provides several APIs to customise many aspects of transitions and animate different components together.
Sequence, Stagger, and Parallel setsβ
Transitions can be composed using the following:
Sequence
- all transitions are run in order. Each transition must end before the following one starts.Stagger
- all transitions are a run in order. There is a fixed delay between starting each transition, and they may overlap.Parallel
- all transitions start at the same time but may end at different times.
The following code uses a stagger
set to animate three different rectangles.
@LayoutSpec
public class StaggerTransitionComponentSpec {
private static final String YELLOW_KEY = "YELLOW_KEY";
private static final String BLUE_KEY = "BLUE_KEY";
private static final String PURPLE_KEY = "PURPLE_KEY";
private static final int PURPLE_COLOR = Color.rgb(144, 29, 191);
@OnCreateLayout
static Component onCreateLayout(ComponentContext c, @State boolean shown) {
return Row.create(c)
.heightPercent(100)
.child(
Row.create(c)
.child(
SolidColor.create(c)
.widthDip(90)
.heightDip(40)
.transitionKey(YELLOW_KEY)
.color(Color.YELLOW))
.child(
SolidColor.create(c)
.widthDip(90)
.heightDip(40)
.transitionKey(BLUE_KEY)
.color(Color.BLUE))
.child(
SolidColor.create(c)
.widthDip(90)
.heightDip(40)
.transitionKey(PURPLE_KEY)
.color(PURPLE_COLOR)))
.clickHandler(StaggerTransitionComponent.onClickEvent(c))
.alignItems(shown ? YogaAlign.FLEX_END : YogaAlign.FLEX_START)
.build();
}
@OnCreateTransition
static Transition onCreateTransition(ComponentContext c) {
return Transition.stagger(
100,
Transition.create(YELLOW_KEY).animate(AnimatedProperties.Y),
Transition.create(BLUE_KEY).animate(AnimatedProperties.Y),
Transition.create(PURPLE_KEY).animate(AnimatedProperties.Y));
}
@OnEvent(ClickEvent.class)
static void onClickEvent(ComponentContext c, @FromEvent View view) {
StaggerTransitionComponent.onUpdateState(c);
}
@OnUpdateState
static void onUpdateState(StateValue<Boolean> shown) {
shown.set(!shown.get());
}
}
The following animation shows this component in action.
Transition sets can be nested within each other, for example, you could have a 'stagger' of 'parallel' animation sets.
Sequences and Staggers support interrupting behaviour, which ensure a component will never jump and will always end up in the correct end position.
The sets can also be used to animate different properties of the same component, as shown in the following example:
@LayoutSpec
public class StaggerTransitionSameComponentSpec {
private static final String YELLOW_KEY = "YELLOW_KEY";
@OnCreateLayout
static Component onCreateLayout(ComponentContext c, @State boolean shown) {
return Row.create(c)
.heightPercent(100)
.child(
Row.create(c)
.child(
SolidColor.create(c)
.widthDip(90)
.heightDip(40)
.transitionKey(YELLOW_KEY)
.color(Color.YELLOW)))
.clickHandler(StaggerTransitionSameComponent.onClickEvent(c))
.justifyContent(shown ? YogaJustify.FLEX_END : YogaJustify.FLEX_START)
.alignItems(shown ? YogaAlign.FLEX_END : YogaAlign.FLEX_START)
.build();
}
@OnCreateTransition
static Transition onCreateTransition(ComponentContext c) {
return Transition.stagger(
50,
Transition.create(YELLOW_KEY).animate(AnimatedProperties.Y),
Transition.create(YELLOW_KEY).animate(AnimatedProperties.X));
}
@OnEvent(ClickEvent.class)
static void onClickEvent(ComponentContext c, @FromEvent View view) {
StaggerTransitionSameComponent.onUpdateState(c);
}
@OnUpdateState
static void onUpdateState(StateValue<Boolean> shown) {
shown.set(!shown.get());
}
}
The following animation shows this component in action.
Animatorsβ
Animators affect the rate in which new values are pushed to the animated components. An Animator
can be added to any transition with the .animator()
builder method.
Litho provides two Animators:
- Spring-based - see the SpringTransitionAnimator
- Timing-based - see the TimingTransitionAnimator
These Animators can be configured to cover most use cases.
It's possible to configure a custom transition by implementing Transition.TransitionAnimator.
By default, all transitions in Litho run by the SpringTransitionAnimator, which is physics based and naturally interruptible. You can tune the parameters of this spring by creating another Animator
using Transition.springWith()
and pass custom tension and friction.
In addition, the TimingTransitionAnimator enables you to set a total time and an Interpolator
. To do this, use the builder Transition.timing()
that receives the total time and an optional Interpolator
.
The default interpolator for the TimingTransitionAnimator is an AccelerateDecelerateInterpolator
.
@OnCreateTransition
static Transition onCreateTransition(ComponentContext c) {
return Transition.parallel(
Transition.create(YELLOW_KEY)
.animate(AnimatedProperties.Y)
.animator(Transition.springWithConfig(120, 12)),
Transition.create(BLUE_KEY).animate(AnimatedProperties.Y).animator(Transition.timing(1000)),
Transition.create(PURPLE_KEY)
.animate(AnimatedProperties.Y)
.animator(Transition.timing(1000, new BounceInterpolator())));
}
The following animation shows this component in action.
TransitionEnd callbackβ
A Listener can be added to receive a callback when an individual transition has ended. This is done through Litho event dispatcher methods (see Events Overview).
The TransitionEndEvent
will be called with the transition key and the specific AnimatedProperty
that has been animated for that key. If multiple instances of AnimatedProperty
are added to the same transition, and all of them run at the same time, a callback will be executed for each. This callback may be useful to loop animations by updating the tree.
@OnEvent(TransitionEndEvent.class)
static void onTransitionEndEvent(
ComponentContext c,
@FromEvent String transitionKey,
@FromEvent AnimatedProperty property,
@State boolean isLooping) {
SequenceTransitionLoopComponent.onUpdateState(c, false);
}
@OnCreateTransition
static Transition onCreateTransition(ComponentContext c) {
return Transition.sequence(
Transition.create(YELLOW_KEY).animate(AnimatedProperties.Y),
Transition.create(BLUE_KEY).animate(AnimatedProperties.Y),
Transition.create(PURPLE_KEY)
.animate(AnimatedProperties.Y)
.transitionEndHandler(SequenceTransitionLoopComponent.onTransitionEndEvent(c)));
}
Many examples can be found in the Litho Sample app: API Demos
->Animation Callbacks
.
A transitionEndHandler
can also be added to Transition.allLayout()
where the same logic applies:
@OnCreateTransition
static Transition onCreateTransition(ComponentContext c) {
return Transition.allLayout().transitionEndHandler(MyComponentSpec.onTransitionEndEvent(c));
}