Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Mysteries of MaterialContainerTransform

Afzal Najam
September 01, 2022
47

Mysteries of MaterialContainerTransform

Presentation about MaterialContainerTransform at Android Developers
Global Summit '22

Afzal Najam

September 01, 2022
Tweet

Transcript

  1. What is Material Container Transform? • Activities • Fragments •

    Views • View <-> Fragment A shared element Transition that transforms one container to another. It can be used to transition between
  2. Customizing MaterialContainerTransform • Start/End ShapeAppearance • Scrim and container colors

    • Fade and Fit modes • Path Motion • Fade Progress thresholds • Scale Mask Progress thresholds • Scale Progress thresholds • Shape Mask Progress thresholds
  3. Controls when in the transition the start (outgoing) view fades

    to the end (incoming) view. Fade Progress Threshold sharedElementEnterTransition = MaterialContainerTransform().apply { fadeProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 0.25f) scaleMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) scaleProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) shapeMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) / / Other options . . . }
  4. Controls when in the transition the start (outgoing) view morphs

    to the end (incoming) view dimensions. Scale Mask Progress Threshold sharedElementEnterTransition = MaterialContainerTransform().apply { fadeProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) scaleMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 0.25f) scaleProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) shapeMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) / / Other options . . . }
  5. Controls when in the transition the contents will scale to

    the dimensions of the end (incoming) view. Scale Progress Threshold sharedElementEnterTransition = MaterialContainerTransform().apply { fadeProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) scaleMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) scaleProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 0.25f) shapeMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) / / Other options . . . }
  6. sharedElementEnterTransition = MaterialContainerTransform().apply { fadeProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f)

    scaleMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) scaleProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 0.25f) shapeMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) / / Other options . . . } Controls when in the transition the contents will scale to the dimensions of the end (incoming) view. Scale Progress Threshold
  7. Shape Mask Progress Threshold Controls when in the transition the

    shape of the start (outgoing) view will morph into the shape of the end (incoming) view. sharedElementEnterTransition = MaterialContainerTransform().apply { fadeProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) scaleMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.75f, 1f) scaleProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 1f) shapeMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 0.75f) / / Other options . . . }
  8. Adjust the views The FAB needs to be centred and

    the end view is positioned above the keyboard. The FAB needs to be centred and round.
  9. Adjust the views The FAB needs to be centred and

    round. <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center_horizontal" android:layout_marginBottom="16dp" android:transitionName="@string/main_activity_fab" app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Material3.Button" app:srcCompat="@android:drawable/ic_dialog_email" / >
  10. Adjust the views The end view should be positioned above

    the keyboard and is smaller. <?xml version="1.0" encoding="utf-8"?> /
  11. Adjust the views <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http : /

    / schemas.android.com/apk/res/android" xmlns:tools="http : / / schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".SecondFragment"> <FrameLayout android:id="@+id/second_container" android:layout_width="match_parent" android:layout_height="320dp" android:layout_gravity=“bottom" android:layout_marginBottom=“220dp” android:background="@drawable/rounded_background" android:padding="16dp" android:transitionName="@string/second_transition_name"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/lorem_ipsum" / > < / FrameLayout> < / FrameLayout> The end view should be positioned above the keyboard and is smaller.
  12. Set fade progress thresholds Prototype doesn’t show true cross- fading

    but we see that the incoming view completely overlaps the FAB around 60ms, which is 20% of the overall transition.
  13. Set fade progress thresholds Prototype doesn’t show true cross- fading

    but we see that the incoming view completely overlaps the FAB around 60ms, which is 20% of the overall transition. sharedElementEnterTransition = MaterialContainerTransform().apply { fadeProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 0.2f) / / Other options and thresholds … }
  14. Set fade progress thresholds Prototype doesn’t show true cross- fading

    but we see that the incoming view completely overlaps the FAB around 60ms, about 20% of the overall transition. sharedElementEnterTransition = MaterialContainerTransform().apply { fadeProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 0.2f) / / Other options and thresholds … }
  15. Set custom interpolator (if needed) Prototype doesn’t show true cross-

    fading but we see that the incoming view completely overlaps the FAB around 0.06s, which is 20% of the overall transition. This prototype uses a custom Path Interpolator. Since ProgressThresholds are dependent on interpolator, it’s better to set it now than later. sharedElementEnterTransition = MaterialContainerTransform().apply { interpolator = PathInterpolator(0.25f, 0.1f, 0.25f, 1f) / / Other options and thresholds … }
  16. Set correct fade progress thresholds After calculating the correct ProgressThresholds

    based on our custom interpolator, the fade animation completes at 60ms. sharedElementEnterTransition = MaterialContainerTransform().apply { interpolator = PathInterpolator(0.25f, 0.1f, 0.25f, 1f) fadeProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 0.295f) / / Other options and thresholds … }
  17. Set correct fade progress thresholds After calculating the correct ProgressThresholds

    based on our custom interpolator, the fade animation completes at 60ms. sharedElementEnterTransition = MaterialContainerTransform().apply { interpolator = PathInterpolator(0.25f, 0.1f, 0.25f, 1f) fadeProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 0.295f) / / Other options and thresholds … }
  18. Set scale mask progress thresholds Prototype doesn’t actually scale the

    FAB so we infer when to start it. Around 40ms, about 13.33% of the overall transition. 0.154 according to our interpolator. sharedElementEnterTransition = MaterialContainerTransform().apply { interpolator = PathInterpolator(0.25f, 0.1f, 0.25f, 1f) fadeProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 0.295f) scaleMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.154f, 1f) / / Other options and thresholds … }
  19. Set scale progress thresholds In the prototype, scaling starts at

    the same time as scale mask so let’s use the same progress thresholds for it. sharedElementEnterTransition = MaterialContainerTransform().apply { interpolator = PathInterpolator(0.25f, 0.1f, 0.25f, 1f) fadeProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 0.295f) scaleMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.154f, 1f) scaleProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.154f, 1f) / / Other options and thresholds … }
  20. Set shape mask progress thresholds The radius animation starts at

    50% in the prototype. For our interpolator, that’s 0.8. sharedElementEnterTransition = MaterialContainerTransform().apply { interpolator = PathInterpolator(0.25f, 0.1f, 0.25f, 1f) fadeProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0f, 0.295f) scaleMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.154f, 1f) scaleProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.154f, 1f) shapeMaskProgressT h resholds = MaterialContainerTransform.ProgressThresholds(0.8f, 1f) / / Other options … }
  21. Return Transition! Recall enter transition thresholds • Fade – 0

    to 0.295 • Scale – 0.154 to 1 • Scale Mask – 0.154 to 1 • Shape Mask – 0.8 to 1 Return transition thresholds
  22. Return Transition! Recall enter transition thresholds • Fade – 0

    to 0.295 • Scale – 0.154 to 1 • Scale Mask – 0.154 to 1 • Shape Mask – 0.8 to 1 Return transition thresholds • Fade – 0.705 to 1 • Scale – 0 to 0.846 • Scale Mask – 0 to 0.846 • Shape Mask – 0 to 0.2
  23. Troubleshooting issues When transition isn't seamless 🤔 If colors aren’t

    fading correctly 💡 Are the container colors correctly set?
  24. Troubleshooting issues When transition isn't seamless 🤔 If colors aren’t

    fading correctly 💡 Are the container colors correctly set? 🤔 If shapes aren’t transitioning correctly 💡 Are start or end ShapeAppearanceModels set?
  25. Troubleshooting issues 🤔 When the return transform doesn't work in

    some cases 💡 Do you need to add a target view?
  26. Links and resources https://github.com/AfzalivE Repo for this talk: https://github.com/AfzalivE/MaterialContainerTransform https://twitter.com/AfzalivE

    • Choosing the Right Transitions by the Material Design team • Animating your keyboard (part 1 ) by Chris Banes • Animating your keyboard (part 2 ) : reacting to WindowInset animations by Chris Banes • WindowInsetsAnimation Sample