Skip to main content

Animation Basics

Introduction​

Within Litho, UI updates are performed by changing state or props on the Component Tree, instead of mutating the views directly. The animation framework adds transitions to components that are triggered when regenerating a tree.

note

It's important to avoid accessing the underlying view to add animations as these values will probably not be preserved.

Transitions can be used to animate view properties when they change between layouts, which is due to a state update or new props from the parent. When changes to a tree occur due to a new state, these changes happen immediately.

The following code and animation show a simple Component that renders a yellow square then aligns it to either the right or left edge of the screen, based on the value of toRight:

override fun ComponentScope.render(): Component {
val toRight = useState { false }
return Column(
style = Style.margin(all = 10.dp).onClick { toRight.update { !it } },
alignItems = if (toRight.value) YogaAlign.FLEX_END else YogaAlign.FLEX_START) {
child(SolidColor.create(context).color(Color.YELLOW).widthDip(80f).heightDip(80f).build())
}
}

When the value of the state changes, the ComponentTree is re-rendered, which makes the square appear to 'jump' from its previous position to the new one. The following section shows how to replace this 'jump' with a transition animation.

Bounds Transitions​

To add bounds animations to all transitioning components between tree changes, use the following:

useTransition(Transition.allLayout())

Transition.allLayout() creates a transition that automatically animates any changes to position, width, or height, as shown in the following animation.

This method only works when changing the bounds of a component. It does not work with:

  • Other properties, including scale, alpha, and rotation.
  • Components being added or removed.

Transitions​

For greater control over the transitions, you can use the following APIs:

  • useTransition - a hook that is used to define the transition animations. It accepts a Transition as its parameter.
  • Transition - a description of the Component/Property (mandatory) and how (optional) you want to animate it. Instead of using a Constructor to create Transition instances, you'll use one of the provided Builders.
  • transitionKey - an identifier that you'd normally assign to a Component that you want to animate. The key is then used when defining Transition.
  • AnimatedProperties - used to target the property of a Component that should be animated when its value changes.

The following sample shows the APIs in use:

override fun ComponentScope.render(): Component {
val isHalfAlpha = useState { false }
useTransition(Transition.create(SQUARE_KEY).animate(AnimatedProperties.ALPHA))
return Column(style = Style.onClick { isHalfAlpha.update { !it } }) {
child(
Row(
style =
Style.transitionKey(context, SQUARE_KEY, Transition.TransitionKeyType.GLOBAL)
.backgroundColor(Color.YELLOW)
.width(80.dp)
.height(80.dp)
.alpha(if (isHalfAlpha.value) 0.5f else 1.0f)))
}
}

The above code features the following:

  • transitionKey- assigned to the component using the Style.transitionKey method.
  • Transition - created using Transition.create() that takes a transitionKey and specifies the property of the component using the .animate() method, which takes an AnimatedProperty. Both of these methods take a variable number of arguments, which means multiple Transitions may be expressed as follows:
private const val SQUARE_KEY: String = "square"
private const val OVAL_KEY: String = "oval"
private const val ANOTHER_SHAPE: String = "another_shape"

// ...
useTransition(
Transition.create(SQUARE_KEY, OVAL_KEY, ANOTHER_SHAPE)
.animate(AnimatedProperties.X, AnimatedProperties.Y))

The following animation shows the AlphaTransitionComponentSpec in action.

The transitions animations API supports three types of transitions: Change, Appear and Disappear, which work differently depending on how the tree changes between states. The example in this page uses a Change transition.