Table of Contents
Understanding Transitions in Android
Transitions in Android define how the visual state of your UI changes between two scenes. A scene is essentially a specific arrangement of views on the screen. Transitions animate the differences between these arrangements so that changes feel smooth and understandable instead of sudden and jarring.
While view and property animations focus on directly changing properties like alpha, translationX, or rotation, transitions work at a higher level. They compare the starting and ending layouts and automatically animate properties for you, such as position, size, and visibility.
This chapter focuses on View-based transitions in the classic View system, not on navigation or activity transitions, which have their own details elsewhere.
Scenes and the Transition Framework
The transition framework is built around the idea of two scenes and a transition between them. A scene represents a snapshot of the view hierarchy in a certain layout. When you move from one scene to another, Android can detect what changed and animate those changes using a transition.
The main classes you will encounter are:
Scene represents the state of a view hierarchy associated with a layout resource or a specific root view.
Transition describes how changes from one scene to another should be animated.
TransitionManager controls when and how transitions run.
You normally define each scene as a separate layout XML file that uses the same root container view. The transition framework then calculates the differences between the two layouts and animates them automatically.
Basic Transition Types
Android provides several built-in transition types that cover common UI changes. These transitions work on specific view properties when they change between two layouts.
AutoTransition is a convenient default transition. It combines Fade for views that appear or disappear and ChangeBounds for views that move or resize. It is often the easiest starting point since it works well for many layout changes without extra configuration.
Fade handles the appearance and disappearance of views by animating their alpha property. If a view exists in the start scene but not in the end scene, or vice versa, Fade will animate the visibility change.
ChangeBounds animates the size and position of views when their layout bounds change between scenes. For example, if a button moves from one side of the screen to another or becomes wider, ChangeBounds animates that movement and resize.
ChangeTransform animates changes to view transformations. This includes scale and rotation, so if a view rotates or scales between scenes, ChangeTransform can animate that change.
ChangeImageTransform is specific to ImageView and animates changes to how the image is displayed inside it. For example, if the scaleType of an ImageView changes between scenes, this transition animates that change.
You can combine multiple transitions into a TransitionSet so that more than one type of change is animated at once.
Defining Transitions in XML
A common way to configure transitions is through XML. You can define a transition resource under res/transition and then apply it in your code. This makes transitions reusable and easier to tweak without recompiling logic code.
A typical XML transition might use AutoTransition or explicitly declare a TransitionSet with child transitions. For example, you might combine Fade and ChangeBounds to handle both visibility and movement. The XML format supports attributes like duration, interpolator, and ordering.
You then load this transition in Kotlin using TransitionInflater.from(context).inflateTransition(R.transition.your_transition_name) and apply it through TransitionManager. Keeping visual behavior in XML also makes it possible to maintain a clear separation between layout structure, animation definitions, and application logic.
Using TransitionManager for Layout Changes
When you want to animate layout changes inside a single scene, you can use TransitionManager with a container view that holds your content. Instead of defining different scenes explicitly, you can let Android take a snapshot of the layout before and after your changes and then animate the differences.
The typical pattern is to call TransitionManager.beginDelayedTransition(container, transition) just before you change layout parameters, visibility, or constraints of the views inside that container. Android captures the "before" state at that moment, then you modify the views, then the framework captures the "after" state and runs the transition.
For example, if you show or hide a panel, change margins, or update the constraints of a ConstraintLayout, the framework can automatically animate those layout changes using the given Transition. This makes it unnecessary to manually animate each property.
Always call TransitionManager.beginDelayedTransition before modifying the views you want to animate. If you call it after changing the layout, Android will not see the original state and the transition will not animate as expected.
If you omit the transition parameter, beginDelayedTransition uses the default AutoTransition, which is often acceptable for simple layout animations. For more control, always provide an explicit transition instance.
Scene-Based Transitions
In some situations, you want to switch between completely different layouts rather than make small tweaks in a single layout. In these cases you can use Scene objects that are associated with layout XML resources.
You typically have a shared root container and two or more layout files. Each layout is turned into a Scene instance. To transition between scenes, you use TransitionManager.go(scene, transition).
When you call this method, Android will:
Capture the current state of the root container.
Inflate the target scene layout into the root.
Compare the old and new states.
Run the given Transition to animate all the differences.
Scene based transitions are useful when you want to switch between different UI arrangements, such as moving from a compact view to a detailed view, changing the entire screen layout, or replacing a group of controls with a different set.
Coordinating Activity and Fragment Transitions
Although activity and fragment transitions have specific APIs, they also rely on similar concepts of capturing starting and ending scenes and animating the changes. Within a single activity, the usual transitions work inside the activity content view, while fragment transitions can add choreography when fragments are added, removed, or replaced.
You can use transitions for shared elements between fragments, where a particular view seems to move from one fragment to another. This creates a feeling that the user moves through a consistent world instead of jumping between unrelated screens. While the detailed APIs for fragment and activity transitions are discussed elsewhere, it is useful to recognize that they are conceptually related to the same transition framework.
Controlling Transition Timing and Interpolators
Transitions support standard timing properties similar to animations. You can set duration to control how long the transition takes, and interpolate the motion to make it feel more natural.
Duration can be set either in XML using an attribute or in code using transition.duration = valueInMillis. Short transitions feel snappy, while longer transitions can feel smoother but may slow down interaction if overused.
Interpolators define the rate of change over time. For example, a linear interpolator changes at a constant speed, while an accelerate decelerate interpolator starts slow, speeds up, then slows again. You can assign interpolators to a transition so that all animated properties follow the same motion curve.
If you combine multiple transitions in a TransitionSet, you can choose whether they play together or in sequence. This lets you create layered effects, where visibility changes happen first, then bounds changes, or vice versa.
Excluding and Targeting Specific Views
Sometimes you do not want every change within a container to be animated. Transitions allow you to control which views are affected. You can include or exclude specific views by ID, by type, or by their relationship in the hierarchy.
Targeting views makes it possible to animate only the key elements that help the user understand what changed, while leaving background or static elements unaffected. This can keep the animation from feeling noisy or distracting.
You can also configure exclusions so that some views are ignored by the transition. For example, you might have a background image that should stay static even if its layout technically changes.
Best Practices for Using Transitions
Transitions are most effective when they clarify what changed, not when they are used just because they look interesting. Use them to support the user’s mental model of the interface.
Focus on key UI elements that represent the main action the user just took. A single clear motion is usually better than many small movements.
Be consistent in duration and style across your app. When similar interactions always produce similar transitions, users can build an intuition about what will happen.
Avoid overlong or overly complex transitions. They can feel slow and may cause frustration, especially on lower end devices. Always consider performance and test on a range of hardware.
Finally, remember that transitions are part of the feedback loop between app and user. When used thoughtfully, they make the experience feel more responsive and understandable without calling attention to themselves.