Motion

Material motion is a set of transition patterns that help users understand and navigate an app. For more information on the patterns and how to choose between them, check out the Material motion system spec.

Before you can use the motion library, you need to add a dependency on the Material Components for Android library (version 1.2.0 or later). For more information, go to the Getting started page.

Note:Motion theming will only be available in Material Components for Android version 1.4.0-alpha01 and above.

Material Components for Android provides support for all four motion patterns defined in the Material spec.

  1. Container transform
  2. Shared axis
  3. Fade through
  4. Fade

The library offers transition classes for these patterns, built on top of both the AndroidX Transition library (androidx.transition) and the Android Transition Framework (android.transition):

AndroidX (preferred)

  • Available in the com.google.android.material.transition package
  • Supports API Level 14+
  • Supports Fragments and Views, but not Activities or Windows
  • Contains backported bug fixes and consistent behavior across API Levels

Platform

  • Available in the com.google.android.material.transition.platform package
  • Supports API Level 21+
  • Supports Fragments, Views, Activities, and Windows
  • Bug fixes not backported and may have different behavior across API Levels

Motion Resources

Container transform

The container transform pattern is designed for transitions between UI elements that include a container. This pattern creates a visible connection between two UI elements.

MaterialContainerTransform is a shared element transition. Unlike traditional Android shared elements, it is not designed around a singular piece of shared content, such as an image, to be moved between two scenes. Instead, the shared element here refers to the bounding container of a start View or ViewGroup (e.g. the entire row layout of an item in a list) transforming its size and shape into that of an end View or ViewGroup (e.g. the root ViewGroup of a full screen Fragment). These start and end container Views are the “shared element” of a container transform. While these containers are being transformed, their contents are swapped to create the transition.

"Container transform gallery - normal speed and slow motion"
Examples of the container transform:

  1. A card into a details page
  2. A list item into a details page
  3. A FAB into a details page
  4. A search bar into expanded search

Using the container transform pattern

A container transform can be configured to transition between a number of Android structures including Fragments, Activities and Views.

Container transform examples

Transition between Fragments

In Fragment A and Fragment B's layouts, identify the start and end Views (as described in the container transform overview) which will be shared. Add a matching transitionName to each of these Views.

Note: There cannot be more than a 1:1 mapping of transitionNames between the start and end layouts. If you have multiple Views in your start layout that could be mapped to an end View in your end layout (e.g. each RecyclerView item to a details screen), read about shared element mapping at Continuous Shared Element Transitions: RecyclerView to ViewPager.

Set Fragment B's sharedElementEnterTransition to a new MaterialContainerTransform. This can be done either before adding/replacing Fragment B into your Fragment container or in Fragment B's onCreate method.

Add or replace Fragment B, adding the shared element from your start scene to your Fragment transaction.

If using the Navigation Architecture Component, use the following.

Completing these steps should give you a working enter and return container transform when navigating from Fragment A to Fragment B and popping from Fragment B to Fragment A.

Note: Fragments are able to define enter and return shared element transitions. When only an enter shared element transition is set, it will be re-used when the Fragment is popped (returns). MaterialContainerTransform internally configures the transition’s properties based on whether or not it’s entering or returning. If you need to customize either the enter or return style of the transition, see Customizing the container transform.

When running this new transition, you might notice that Fragment A (everything besides the shared element) disappears as soon as the container transform starts. This is because FragmentA has been removed from its container. To “hold” FragmentA in place as the container transform plays, set FragmentA's exit transition to the the provided Hold transition.

Note: When setting a Hold or MaterialElevationScale transition, it’s important that the transition matches the duration of the MaterialContainerTransform it’s paired with. If explicitly setting a duration on MaterialContainerTransform with setDuration, use the same value. Otherwise, prefer the MaterialContainerTransform(Context, boolean) constructor which loads theme-based values upfront so Hold or MaterialElevationScale’s duration can be accurately set using MaterialContainerTransform.getDuration.

Alternatively, to subtly scale and fade Fragment A while the container transform is playing, set FragmentA's exit and reenter transitions to a MaterialElevationScale transition. This will help to reinforce the spatial relationship and navigational hierarchy of the two screens along the z-axis.

We pass in false for the exit MaterialElevationScalegrowing constructor param, to scale down or shrink Fragment A when it is exiting during the enter container transform. Whereas we pass in true for the reenter MaterialElevationScale to scale up or expand Fragment A when it is reentering during the return container transform.

Note: When using MaterialElevationScale, make sure to mark the root view of your Fragment as a transition group, either with android:transitionGroup="true" for API level 21+ or ViewGroupCompat#setTransitionGroup for all API levels. This will ensure that the animation is applied to the Fragment view as a whole, as opposed to each child view individually, which is the default behavior of the Android Transitions system.

Transition between Activities

Note: Activity and Window transitions require using Android Framework Transitions provided in the com.google.android.material.transition.platform package and are only available on API level 21 and above.

In Activity A’s layout, identify the start View to be used as the “shared element” as described in the container transform overview. Give the start view a transitionName.

Configure Activity A for an exit shared element transition as follows:

In Activity B, configure the Activity for transitions in a similar fashion.

Note: We are using android.R.id.content (the window’s root) as the shared element “container” in Activity B. This will cause the start view from Activity A to transition into the full screen of Activity B. If you have views in Activity A and Activity B that you do not want included as part of the transform, you can alternatively set the transition name on a View/ViewGroup in Activity B’s layout or include/exclude Views with helper methods on the Transition class (Transition#addTarget, Transition#excludeChildren, etc).

From Activity A, start the container transform by constructing an Intent with the following options.

Transition between Views

In the Activity or Fragment where you are transitioning between two views, trigger a MaterialContainerTransform by manually setting the transition’s start and end Views.

This will perform a container transform from the start view transitioning to the end view. To return, set up the same transform, switching the start and end Views and undoing any property changes (setting the FAB back to View.VISIBLE and the bottomToolbar back to View.GONE) done by the first transform.

Customization

While the out-of-the-box container transform should work in most cases, you can manually set the following properties on MaterialContainerTransform to customize the look and feel of the animation:

Container transform attributes

ElementAttributeRelated method(s)Default value
ShapetransitionShapeAppearancegetStartShapeAppearanceModel
setStartShapeAppearanceModel
getEndShapeAppearanceModel
setEndShapeAppearanceModel
null
Duration (incoming)motionDurationLong1getDuration
setDuration
300ms
Duration (outgoing)motionDurationMedium2getDuration
setDuration
250ms
EasingmotionEasingStandardgetInterpolator
setInterpolator
cubic-bezier(0.4, 0.0, 0.2, 1)
FastOutSlowIn
Motion pathmotionPathgetPathMotion
setPathMotion
linear

Note: By default, MaterialContainerTransform uses different durations when incoming vs. outgoing. Calling setDuration on an instance of MaterialContainerTransform will override this behavior, causing the passed duration to be used both when incoming and outgoing. If you would like different durations for incoming and outgoing animations, you should create and set separate instances of MaterialContainerTransform for entering and returning transitions with the desired values. Alternatively, update the duration theme attributes.

MaterialContainerTransform provides two constructors - an empty parameter constructor and a (Context, boolean) constructor. The (Context, boolean) constructor is used to load theme-values upfront, making it possible to query for duration, interpolation and motion path if other transitions or animations, such as Hold and MaterialElevationScale, depend on these values from MaterialContainerTransform.

See the Motion Theming section for details on how to systematically update motion.

Container transform properties

ElementRelated method(s)Default value
DurationgetDuration
setDuration
300
InterpolationgetInterpolation
setInterpolation
R.interpolator.fast_out_slow_in
Path MotiongetPathMotion
setPathMotion
null (Linear)
Z OrdergetDrawingViewId
setDrawingViewId
android.R.id.content
Container Background ColorgetContainerColor
setContainerColor
Color.TRANSPARENT
Container Start View Background ColorgetStartContainerColor
setStartContainerColor
Color.TRANSPARENT
Container End View Background ColorgetEndContainerColor
setEndContainerColor
Color.TRANSPARENT
Scrim ColorgetScrimColor
setScrimColor
#52000000 (32% opacity, black)
DirectiongetTransitionDirection
setTransitionDirection
MaterialContainerTransform.TRANSITION_DIRECTION_AUTO
Fade ModegetFadeMode
setFadeMode
MaterialContainerTransform.FADE_MODE_IN
Fit ModegetFitMode
setFitMode
MaterialContainerTransform.FIT_MODE_AUTO
Fade ThresholdsgetFadeProgressThresholds
setFadeProgressThresholds
[0.0 - 0.25] enter
[0.6 - 0.9] return
[0.1 - 0.4] enter w. arc
[0.6 - 0.9] return w. arc
Scale ThresholdsgetScaleProgressThresholds
setScaleProgressThresholds
[0.0 - 1.0] enter
[0.0 - 1.0] return
[0.1 - 1.0] enter w. arc
[0.0 - 0.9] return w. arc
Scale Mask ThresholdsgetScaleMaskProgressThresholds
setScaleMaskProgressThresholds
[0.0 - 1.0] enter
[0.0 - 0.9] return
[0.1 - 1.0] enter w. arc
[0.0 - 0.9] return w. arc
Shape Mask ThresholdsgetShapeMaskProgressThresholds
setShapeMaskProgressThresholds
[0.0 - 0.75] enter
[0.3 - 0.9] return
[0.1 - 0.9] enter w. arc
[0.2 - 0.9] return w. arc
Debug DrawingisDrawDebugEnabled()
setDrawDebugEnabled()
false

Note: All of these properties have defaults. In most cases, each property has a different default value depending on whether or not the transition is entering or returning.

When you manually set any of the above properties, the value set will be used when the transition is both entering and returning (including when an enter transition is being re-used due to no return being set). If you need to manually set properties which differ depending on whether or not the transition is entering or returning, create two MaterialContainerTransforms and set both the sharedElementEnterTransition and sharedElementReturnTransition.

Fade Through Variant

MaterialContainerTransform supports the "Container transform: fade through variant" mentioned in the spec, which will sequentially fade out and in the outgoing and incoming views, respectively, in order to minimize the visual overlap of these views. This variant can be achieved with the following Fade Mode configuration:

If using the fade through variant, consider also tweaking the MaterialContainerTransform's Fade Thresholds property. For example, to make the container transform's fade through happen over the full duration of the transition, use the following Fade Thresholds configuration:

Shared axis

The shared axis pattern is used for transitions between UI elements that have a spatial or navigational relationship. This pattern uses a shared transformation on the x, y, or z axis to reinforce the relationship between elements.

"Shared axis gallery - normal speed and slow motion"
Examples of the shared axis pattern:

  1. An onboarding flow transitions along the x-axis
  2. A stepper transitions along the y-axis
  3. A parent-child navigation transitions along the z-axis

Using the shared axis pattern

MaterialSharedAxis is a Visibility transition. A Visibility transition is triggered when the target View's visibility is changed or when the View is added or removed. This means MaterialSharedAxis requires a View to be changing in visibility or to be added or removed to trigger its animation.

MaterialSharedAxis uses the concept of moving in the forward or backward direction. Below are the directions in which a MaterialSharedAxis will move for both the forward and backward directions along each axis.

Shared axis direction

AxisForwardBackward
XLeft on x-axisRight on x-axis
YUp on y-axisDown on y-axis
ZForward on z-axisBackward on z-axis

Note: Since a shared axis' direction is independent of whether its target is appearing or dissapearing (an appearing target will sometimes be moving forward when entering and forward when exiting), MaterialSharedAxis is not able to automatically reverse when only a target's enter transition is set. For this reason, you should manually configure and set a target's transitions (enter ,exit, return, reenter) with the correct direction.

A shared axis transition can be configured to transition between a number of Android structures including Fragments, Activities and Views.

Shared axis examples

Transition between Fragments

In the following example, we’re creating a shared axis Z transition between FragmentA and FragmentB. Moving from FragmentA to FragmentB should be a “forward” movement and returning from FragmentB to FragmentA should be a “backward” movement.

In Fragment A, configure an enter and exit transition.

In Fragment B, again configure an enter and exit transition.

It’s important to note here how these two fragments move together. When Fragment A is exiting, Fragment B will be entering. This is why, in Fragment A, the exit transition is forward = true and in Fragment B the enter transition is also forward = true. This will ensure that both Fragments are moving in the same direction when these transition pairs are running. The opposite is true in the backwards direction. When Fragment B is exiting, Fragment A will be reentering. For this reason, Fragment B is configured to exit in the backward direction and Fragment A is configured to reenter in the backward direction.

When you're ready to move from Fragment A to B, replace Fragment A with Fragment B.

The above should give you a working shared axis transition between Fragment A and Fragment B. Changing the axis to MaterialSharedAxis.X or MaterialSharedAxis.Y will create the same, coordinated interaction in their respective axis. Alternatively, try replacing MaterialSharedAxis with a MaterialFadeThrough for a transition between destinations or layouts that are not spatially related.

Transition between Activities

Note: Activity and Window transitions require using Android Framework Transitions provided in the com.google.android.material.transition.platform package and are only available on API level 21 and above.

Enable Activity transitions by either setting android:windowActivityTransitions to true in your theme or enabling them on an Activity by Activity basis by setting the Window.FEATURE_ACTIVITY_TRANSITIONS flag.

Or in your Activities:

To get started, configure a new shared axis transition in Activity A and set it as the Activity's exitTransition.

You can optionally add or exclude targets to have the transition affect or ignore Views. Use the combination you need to have the transition applied where desired. For example:

Next, configure a new MaterialSharedAxis enter transition in Activity B.

When you're ready to navigate from Activity A to Activity B, start Activity B like your normally would, passing in an ActivityOptionsBundle.

Transition between Views

In your Activity or Fragment’s layout, identify the two views which will be “swapped”. The outgoing View should be added to the layout and visible. The incoming View's visibility should either be set to View.GONE or the View should not yet be added to the layout. When you’re ready to replace the outgoing view with the incoming View, do so with a shared axis transition as follows.

This will transition between your outgoing and incoming Views with a shared axis transition. To reverse the animation, set up a new shared axis in the opposite direction and set your outgoing View back to View.VISIBLE and your incoming View back to View.GONE.

Customization

MaterialSharedAxis is an extension of MaterialVisibility. MaterialVisibility is a Visibility transition composed of smaller, "atomic" VisibilityAnimatorProviders. These providers are classes which can be configured and are able to construct an animator depending on whether a target is appearing or disappearing. By default, a MaterialVisibility implementation has a primary and secondary VisibilityAnimatorProvider. The primary provider can be modified while the secondary provider can be either modified, replaced or removed. This allows for the customization of Material motion while still adhering to a pattern's foundation and is refered to as a variant.

Shared axis composition

ElementPrimary transitionSecondary transition
MaterialSharedAxisX -SlideDistance
Y -SlideDistance
Z -Scale
FadeThrough

Shared axis fade variant

The following is a MaterialSharedAxis Z transition between Activities which fades Activity B in and over Activity A while leaving Activity A’s alpha unchanged. This can be accomplished by removing the secondary FadeThroughProvider from Activity A's exit transition.

Shared axis attributes

ElementAttributeRelated method(s)Default value
DurationmotionDurationLong1getDuration
setDuration
300ms
EasingmotionEasingStandardgetInterpolator
setInterpolator
cubic-bezier(0.4, 0.0, 0.2, 1)
FastOutSlowIn

See the Motion Theming section for details on how to systematically update motion.

Fade Through

The fade through pattern is used for transitions between UI elements that do not have a strong relationship to each other.

"Fade through gallery - normal speed and slow motion"
Examples of the fade through pattern:

  1. Tapping destinations in a bottom navigation bar
  2. Tapping a refresh icon
  3. Tapping an account switcher

Using the fade through pattern

MaterialFadeThrough is a Visibility transition. A Visibility transition is triggered when the target View's visibility is changed or when the View is added or removed. This means MaterialFadeThrough requires a View to be changing in visibility or to be added or removed to trigger its animation.

A fade through can be configured to transition between a number of Android structures including Fragments, Activities and Views.

Fade through examples

Transition between Fragments

In Fragment A, configure an exit MaterialFadeThrough transition and in Fragment B configure an enter MaterialFadeThrough transition. Both of these will be used (and reused) when navigating from Fragment A to Fragment B and from Fragment B to Fragment A.

Note: Since MaterialFadeThrough extends Visibility, MaterialFadeThrough is able to appropriately animate targets depending on whether they are apperaing or disappearing.

When you're ready to navigate between Fragment A and Fragment B, use a standard Fragment transaction or use the Navigation Component.

Transition between Activities

Note: Activity and Window transitions require using Android Framework Transitions provided in the com.google.android.material.transition.platform package and are only available on API level 21 and above.

Enable Activity transitions by either setting android:windowActivityTransitions to true in your theme or enabling them on an Activity-by-Activity basis by setting the Window.FEATURE_ACTIVITY_TRANSITIONS flag.

Or in your Activities:

To get started, configure a new MaterialFadeThrough in Activity A and set it as the Activity's exitTransition.

You can optionally add or exclude targets to have the transition affect or ignore Views. Use the combination you need to have the transition applied where you’d like. For example:

Next, configure a new MaterialFadeThrough enter transition in Activity B.

When you're ready to navigate from Activity A to Activity B, start Activity B as your normally would, passing in an ActivityOptionsBundle.

Transition between Views

In your Activity or Fragment’s layout, identify the two Views which will be “swapped”. The outgoing View should be added to the layout and visible. The incoming View should either be set to View.GONE or not yet added to the layout. When you’re ready to replace the outgoing View with the incoming View, do so with a fade through transition as follows.

This will transition between your outgoing and incoming Views with a fade through transition. To reverse the animation, follow the same steps, setting your outgoing View back to View.VISIBLE and your incoming View back to View.GONE.

Customization

MaterialFadeThrough is an extension of MaterialVisibility. MaterialVisibility is a Visibility transition composed of smaller, "atomic" VisibilityAnimatorProviders. These providers are classes which can be configured and are able to construct an animator depending on whether a target is appearing or disappearing. By default, a MaterialVisibility implementation has a primary and secondary VisibilityAnimatorProvider. The primary provider can be modified while the secondary provider can be either modified, replaced or removed. This allows for the customization of Material motion while still adhering to a pattern's foundation and is refered to as a variant.

Fade through composition

ElementPrimary transitionSecondary transition
MaterialFadeThroughFadeThroughScale

Fade through slide variant

The below will create a fade through between Fragments which fades Fragment A out (without a scale) and fades Fragment B in with a slide instead of a scale.

Fade through attributes

ElementAttributeRelated method(s)Default value
DurationmotionDurationLong1getDuration
setDuration
300ms
EasingmotionEasingStandardgetInterpolator
setInterpolator
cubic-bezier(0.4, 0.0, 0.2, 1)
FastOutSlowIn

See the Motion Theming section for details on how to systematically update motion.

Fade

The fade pattern is used for UI elements that enter or exit within the bounds of the screen, such as a dialog that fades in the center of the screen.

"Fade gallery - normal speed and slow motion"
Examples of the fade pattern:

  1. A dialog
  2. A menu
  3. A snackbar
  4. A FAB

Using the fade pattern

MaterialFade is a Visibility transition. A Visibility transition is triggered when the target View's visibility is changed or when the View is added or removed. This means MaterialFade requires a View to be changing in visibility or to be added or removed to trigger its animation.

Fade examples

Transition a View

In your Activity or Fragment, toggle the visibility of your target View, in this case a Floating Action Button, using a MaterialFade to animate the change.

When reversing the transition, configure and trigger a MaterialFade in the same manner, making any adjustments to the transition that differ when entering versus exiting.

Customization

MaterialFade is an extension of MaterialVisibility. MaterialVisibility is a Visibility transition composed of smaller, "atomic" VisibilityAnimatorProviders. These providers are classes which can be configured and are able to construct an animator depending on whether a target is appearing or disappearing. By default, a MaterialVisibility implementation has a primary and secondary VisibilityAnimatorProvider. The primary provider can be modified while the secondary provider can be either modified, replaced or removed. This allows for the customization of Material motion while still adhering to a pattern's foundation and is refered to as a variant.

Fade composition

ElementPrimary transitionSecondary transition
MaterialFadeFadeScale

Fade through attributes

ElementAttributeRelated method(s)Default value
Duration (incoming)motionDurationShort2getDuration
setDuration
150ms
Duration (outgoing)motionDurationShort1getDuration
setDuration
75ms
EasingmotionEasingLineargetInterpolator
setInterpolator
cubic-bezier(0 0, 1, 1)
Linear

See the Motion Theming section for details on how to systematically update motion.

Theming

Motion theming will only be available in Material Components for Android version 1.4.0-alpha01 and above.

The Material motion system is backed by a limited number of slots which transitions use by default to create a consistent, branded feel. These slots are implemented as theme attributes, similar to color or shape attributes.

Easing

Easing theme attributes define a set of curves that can be inflated and used as Interpolators.

AttributeDefault valueDescription
?attr/motionEasingStandardcubic-bezier(0.4, 0.0, 0.2, 1)
FastOutSlowIn
Easing used for elements that begin and end at rest.
?attr/motionEasingEmphasizedpath(M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1)
FastOutExtraSlowIn
Easing used for elements that begin and end at rest but want extra attention drawn to the end of the animation.
?attr/motionEasingDeceleratedcubic-bezier(0.0, 0.0, 0.2, 1)
LinearOutSlowIn
Easing used for incoming elements; motion begins at peak velocity and ends at rest.
?attr/motionEasingAcceleratedcubic-bezier(0.4, 0.0, 1, 1)
FastOutLinearIn
Easing used for outgoing elements; motion begins at rest and ends at peak velocity.
?attr/motionEasingLinearcubic-bezier(0, 0, 1, 1)
Linear
Easing for simple motion such as fading.

Easing attributes are able to accept two types of curves - cubic beziers and vector paths. Cubic bezier curves are in the standard (x1, y1, x2, y2) format. For vector path curves, the curve must start at 0,0 and end at 1, 1. Vector path curves can be beneficial if you’d like to introduce 3-point (quintic) easing curves to your app in a backwards compatible way.

To update an easing value override any of the attributes in your app’s theme following the <type>(value) string format.

For more information on easing, see material.io/design/motion/customization.html#applying-customizations.

Duration

Duration attributes are a set of durations in milliseconds that can be used for animations.

AttributeDefault valueDescription
?attr/motionDurationShort175msDuration for use with small motion areas such as icons and selection controls.
?attr/motionDurationShort2150ms
?attr/motionDurationMedium1200msDuration for use with large motion areas such as bottom sheets and expanding chips.
?attr/motionDurationMedium2250ms
?attr/motionDurationLong1300msDuration for use with elements that traverse a large portion of the screen, such as page transitions.
?attr/motionDurationLong2350ms

In general, durations should increase in duration as the area/traversal of an animation increases. Maintaining this rule when customizing duration attributes will ensure your transitions have a consistent sense of speed.

To override a duration attribute, assign the attribute to your desired millisecond integer value.

For more information on duration, see material.io/design/motion/customization.html#speed

Path

Path attributes are values which control the behavior of animating elements.

AttributeDefault valueDescription
?attr/motionPathlinearAn enum that controls the path along which animating elements move.
linear: Elements move along a straight path from their current position to their new position. A linear path corresponds to a nullPathMotion.
arc: Elements move along a curved/arced path. An arc path corresponds to a MaterialArcMotionPathMotion.

For more information of motionPath, see material.io/design/motion/customization.html#motion-paths

Up next