Motion Layout : Make your apps move auto-magically

Motion Layout : Make your apps move auto-magically

Motion Layout is introduced in ConstraintLayout 2.0 and it gives a lot of flexibility to make animations and transitions.

C4db14b923561bc57fc10725abbecbcf?s=128

Lin Min Phyo

July 09, 2019
Tweet

Transcript

  1. Motion Layout : Make your apps move auto-magically @Linminphyoe1

  2. About the talk • A walkthrough to sample app •

    Strategy for building an interactive animations easily • Learning approaches to
 Motion Layout • Tips and tricks
  3. Who am I ? Lin Min Phyo Senior Android Developer

    Product, UI/UX, Software Architectures
  4. Motion Layout Make your apps move auto-magically

  5. Motion Layout class MotionLayout extends ConstraintLayout

  6. Back to the past

  7. Before Constraint Layout Building UI is hard

  8. • Nested Hierarchy • Non-functional Design View • Not Flexible

    Before Constraint Layout
  9. Constraint Layout 1.x Which problems are solved?

  10. Constraint Layout 1.x Flatter Hierarchy

  11. Constraint Layout 1.x Flatter Hierarchy

  12. Constraint Layout 1.x • Easy positioning views • Guidelines •

    Chains • Bias • Many utilities and functionalities Features Highlights https://developer.android.com/reference/android/support/constraint/ConstraintLayout
  13. Constraint Layout 1.x How?

  14. Constraint Layout 1.x • Connections between views • Connections between

    view and parent view group • Connections between view and helper views Constraints
  15. Constraints <Button android:id=“@+id/A” /> A

  16. Constraints <Button android:id=“@+id/A” /> <Button android:id=“@+id/B” /> A B

  17. Constraints <Button android:id=“@+id/A” /> <Button android:id=“@+id/B” /> A B

  18. Constraints <Button android:id=“@+id/A” /> <Button android:id=“@+id/B” app:layout_constraintStart_toEndOf=“@+id/A” /> A B

  19. Constraints <Button android:id=“@+id/A” /> A

  20. Constraints <Button android:id=“@+id/A” /> <Button android:id=“@+id/B” /> B A

  21. Constraints <Button android:id=“@+id/A” /> <Button android:id=“@+id/B” /> B A

  22. Constraints A B <Button android:id=“@+id/A” /> <Button android:id=“@+id/B” app:layout_constraintStart_toStartOf=“@+id/A” />

  23. Constraints <Button android:id=“@+id/B" app:layout_constraintStart_toStartOf=“parent” /> B

  24. Constraints

  25. Guidelines <androidx.constraintlayout.widget.Guideline android:layout_width="wrap_content" android:layout_height=“wrap_content” />

  26. Guidelines <androidx.constraintlayout.widget.Guideline android:layout_width="wrap_content" android:layout_height=“wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent=“.30” />

  27. Guidelines <androidx.constraintlayout.widget.Guideline android:layout_width="wrap_content" android:layout_height=“wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent=“.60” />

  28. Guidelines <androidx.constraintlayout.widget.Guideline android:layout_width="wrap_content" android:layout_height=“wrap_content" android:orientation=“horizontal" app:layout_constraintGuide_percent=“.40” />

  29. Transitions How transitions work

  30. How transitions work

  31. Start State End State Transition How transitions work

  32. How transitions work Start State End State Transition

  33. Constraint Sets Made animation easy

  34. state_one.xml Constraint Sets

  35. state_one.xml state_two.xml Constraint Sets

  36. Constraint Sets Activity.kt

  37. Constraint Sets ConstraintSet constraintSet1 = new ConstraintSet(); ConstraintSet constraintSet2 =

    new ConstraintSet(); Activity.kt
  38. Constraint Sets ConstraintSet constraintSet1 = new ConstraintSet(); ConstraintSet constraintSet2 =

    new ConstraintSet(); constraintSet1.clone(context, R.layout.state_one); constraintSet2.clone(context, R.layout.state_two); Activity.kt
  39. Constraint Sets ConstraintSet constraintSet1 = new ConstraintSet(); ConstraintSet constraintSet2 =

    new ConstraintSet(); constraintSet1.clone(context, R.layout.state_one); constraintSet2.clone(context, R.layout.state_two); poster.setOnClickListener { if (nowAtStateTwo) { constraintSet1.applyTo(contentView); } else { constraintSet2.applyTo(contentView); } } Activity.kt
  40. Constraint Sets ConstraintSet constraintSet1 = new ConstraintSet(); ConstraintSet constraintSet2 =

    new ConstraintSet(); constraintSet1.clone(context, R.layout.state_one); constraintSet2.clone(context, R.layout.state_two); TransitionManager.beginDelayedTransition(contentView); poster.setOnClickListener { if (nowAtStateTwo) { constraintSet1.applyTo(contentView); } else { constraintSet2.applyTo(contentView); } } Activity.kt
  41. Constraint Layout 2.x More goodness

  42. Constraint Layout 2.x • Linear helper • Flow • ImageFilterView

    • Layer • Mock View • Decorators • Motion Layout Official docs @ https://developer.android.com/reference/android/support/constraint/classes
  43. Motion Layout One layout to rule them all

  44. Motion Layout class MotionLayout extends ConstraintLayout

  45. @layout/state_one.xml @layout/state_two.xml package/activity.kt Constraint Sets Motion Layout @layout/layout.xml VS

  46. @layout/state_one.xml @layout/state_two.xml package/activity.kt Constraint Sets Motion Layout @layout/layout.xml VS Views

    of the layout
  47. @layout/state_one.xml @layout/state_two.xml package/activity.kt Constraint Sets Motion Layout @layout/layout.xml @xml/motion.xml VS

    View attributes and transitions
  48. @layout/state_one.xml @layout/state_two.xml package/activity.kt Constraint Sets Motion Layout @layout/layout.xml @layout/motion.xml package/activity.kt

    VS [ Optional ]
  49. Sample App

  50. Movie Poster @layout/layout_poster.xml @xml/motion_poster.xml

  51. <androidx.constraintlayout.motion.widget.MotionLayout android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/motion_poster"> </androidx.constraintlayout.motion.widget.MotionLayout> @layout/layout_poster.xml

  52. <androidx.constraintlayout.motion.widget.MotionLayout android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/motion_poster"> </androidx.constraintlayout.motion.widget.MotionLayout> @layout/layout_poster.xml

  53. <androidx.constraintlayout.motion.widget.MotionLayout android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/motion_poster"> </androidx.constraintlayout.motion.widget.MotionLayout> @layout/layout_poster.xml

  54. <androidx.constraintlayout.motion.widget.MotionLayout android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/motion_poster"> <com.google.android.material.card.MaterialCardView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/card_movie_poster" app:layout_constraintDimensionRatio="2:3" >

    <ImageView android:id="@+id/image_poster" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/poster_endgame" /> </com.google.android.material.card.MaterialCardView> </androidx.constraintlayout.motion.widget.MotionLayout> @layout/layout_poster.xml
  55. <androidx.constraintlayout.motion.widget.MotionLayout android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/motion_poster"> <com.google.android.material.card.MaterialCardView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/card_movie_poster" app:layout_constraintDimensionRatio="2:3" >

    <ImageView android:id="@+id/image_poster" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/poster_endgame" /> </com.google.android.material.card.MaterialCardView> </androidx.constraintlayout.motion.widget.MotionLayout> @layout/layout_poster.xml
  56. android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/poster_endgame" /> </com.google.android.material.card.MaterialCardView> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_horizontal_10" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"

    app:layout_constraintGuide_percent=".10"/> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_vertical_52" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent=".52"/> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_vertical_48" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent=“.48"/> </androidx.constraintlayout.motion.widget.MotionLayout> @layout/layout_poster.xml
  57. android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/poster_endgame" /> </com.google.android.material.card.MaterialCardView> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_horizontal_10" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"

    app:layout_constraintGuide_percent=".10"/> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_vertical_52" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent=".52"/> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_vertical_48" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent=“.48"/> </androidx.constraintlayout.motion.widget.MotionLayout> @layout/layout_poster.xml
  58. android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/poster_endgame" /> </com.google.android.material.card.MaterialCardView> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_horizontal_10" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"

    app:layout_constraintGuide_percent=".10"/> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_vertical_52" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent=".52"/> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline_vertical_48" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent=“.48"/> </androidx.constraintlayout.motion.widget.MotionLayout> @layout/layout_poster.xml
  59. Movie Poster @layout/layout_poster.xml @xml/motion_poster.xml

  60. Movie Poster ✔ @layout/layout_poster.xml @xml/motion_poster.xml

  61. @xml/motion_poster.xml

  62. @xml/motion_poster.xml Start State End State Transition

  63. Start State @xml/motion_poster.xml <MotionScene> </MotionScene>

  64. MotionScene XML for holding views’ attributes and transitions

  65. MotionScene <ConstraintSet> <Transition> <StateSet> (Optional)

  66. MotionScene <ConstraintSet> <Transition> <StateSet> (Optional) Hold view attributes

  67. MotionScene <ConstraintSet> <Transition> <StateSet> (Optional) Define start frame, end frame

    and transition information
  68. MotionScene <ConstraintSet> <Transition> <StateSet> (Optional) Group of states defined for

    different screens
  69. Start State @xml/motion_poster.xml <MotionScene> </MotionScene>

  70. Start State @xml/motion_poster.xml <MotionScene> <ConstraintSet android:id="@+id/frame_poster_top"> </ConstraintSet> </MotionScene>

  71. Start State @xml/motion_poster.xml <MotionScene> <ConstraintSet android:id="@+id/frame_poster_top"> <Constraint android:id="@+id/card_movie_poster"> </Constraint> </ConstraintSet>

    </MotionScene>
  72. Constraints Attributes of a view

  73. Constraint Attributes Layout Transform Property Motion CustomAttribute

  74. Constraint Attributes Layout Transform Property Motion CustomAttribute View Positioning Attributes

  75. Constraint Attributes Layout Transform Property Motion CustomAttribute Rotations, re-sizings, translation

  76. Constraint Attributes Layout Transform Property Motion CustomAttribute Alpha, Visibility

  77. Constraint Attributes Layout Transform Property Motion CustomAttribute Path Rotation, Easing

  78. Constraint Attributes Layout Transform Property Motion CustomAttribute View attributes with

    reflection
  79. Start State @xml/motion_poster.xml <MotionScene> <ConstraintSet android:id="@+id/frame_poster_top"> <Constraint android:id="@+id/card_movie_poster"> </Constraint> </ConstraintSet>

    </MotionScene>
  80. Start State @xml/motion_poster.xml <MotionScene> <ConstraintSet android:id="@+id/frame_poster_top"> <Constraint android:id="@+id/card_movie_poster"> <Layout android:layout_width="0dp"

    android:layout_height="0dp" android:layout_marginStart=“24dp” app:layout_constraintDimensionRatio=“2:3" app:layout_constraintStart_toStartOf=“parent" app:layout_constraintEnd_toStartOf=“@+id/guide_y_52" app:layout_constraintTop_toTopOf=“@+id/guide_x_10”/> </Constraint> </ConstraintSet> </MotionScene>
  81. @xml/motion_poster.xml Start State End State Transition

  82. <MotionScene> <ConstraintSet android:id=“@+id/frame_poster_top"> <Constraint android:id=“@+id/card_movie_poster"> <Layout android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="24dp" app:layout_constraintDimensionRatio=“2:3"

    app:layout_constraintStart_toStartOf=“parent" app:layout_constraintEnd_toStartOf="@+id/guide_y_52" app:layout_constraintTop_toTopOf=“@+id/guide_x_10”/> </Constraint> </ConstraintSet> </MotionScene> End State @xml/motion_poster.xml
  83. <Layout android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="24dp" app:layout_constraintDimensionRatio=“2:3" app:layout_constraintStart_toStartOf=“parent" app:layout_constraintEnd_toStartOf="@+id/guide_y_52" app:layout_constraintTop_toTopOf=“@+id/guide_x_10”/> </Constraint> </ConstraintSet>

    <ConstraintSet android:id=“@+id/frame_poster_middle"> </ConstraintSet> </MotionScene> End State @xml/motion_poster.xml
  84. android:layout_width="0dp" android:layout_height="0dp" android:layout_marginStart="24dp" app:layout_constraintDimensionRatio=“2:3" app:layout_constraintStart_toStartOf=“parent" app:layout_constraintEnd_toStartOf=“@+id/guide_y_52" app:layout_constraintTop_toTopOf=“@+id/guide_x_10”/> </Constraint> </ConstraintSet> <ConstraintSet

    android:id=“@+id/frame_poster_middle"> <Constraint android:id=“@+id/card_movie_poster"> </Constraint> </ConstraintSet> </MotionScene> End State @xml/motion_poster.xml
  85. app:layout_constraintStart_toStartOf=“parent" app:layout_constraintEnd_toStartOf=“@+id/guide_y_52" app:layout_constraintTop_toTopOf=“@+id/guide_x_10”/> </Constraint> </ConstraintSet> <ConstraintSet android:id=“@+id/frame_poster_middle"> <Constraint android:id=“@+id/card_movie_poster"> <Layout

    android:layout_width="0dp" android:layout_height="0dp" android:layout_marginEnd="24dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="2:3" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@+id/guide_y_48" app:layout_constraintTop_toTopOf=“parent"/> </Constraint> </ConstraintSet> </MotionScene> End State @xml/motion_poster.xml
  86. Start State End State Transition @xml/motion_poster.xml

  87. Transition @xml/motion_poster.xml <MotionScene> <ConstraintSet android:id="@+id/frame_poster_top"> ••• </ConstraintSet> <ConstraintSet android:id="@+id/frame_poster_middle"> •••

    </ConstraintSet> </MotionScene>
  88. @xml/motion_poster.xml <MotionScene> <Transition android:id=“@+id/transition_poster" app:constraintSetStart="@+id/frame_poster_top" app:constraintSetEnd=“@+id/frame_poster_middle" > </Transition> <ConstraintSet android:id="@+id/frame_poster_top">

    ••• </ConstraintSet> <ConstraintSet android:id="@+id/frame_poster_middle"> ••• </ConstraintSet> </MotionScene> Transition
  89. Transition Describe start frame, end frame and transition informations

  90. Transition constraintSetStart constraintSetEnd motionInterpolator duration <OnSwipe> <OnClick> <KeyFrameSet>

  91. Transition constraintSetStart constraintSetEnd motionInterpolator duration <OnSwipe> <OnClick> <KeyFrameSet>

  92. Transition constraintSetStart constraintSetEnd motionInterpolator duration <OnSwipe> <OnClick> <KeyFrameSet>

  93. Transition constraintSetStart constraintSetEnd motionInterpolator duration <OnSwipe> <OnClick> <KeyFrameSet> Transition easing

  94. Transition constraintSetStart constraintSetEnd motionInterpolator duration <OnSwipe> <OnClick> <KeyFrameSet>

  95. Transition constraintSetStart constraintSetEnd motionInterpolator duration <OnSwipe> <OnClick> <KeyFrameSet>

  96. Transition constraintSetStart constraintSetEnd motionInterpolator duration <OnSwipe> <OnClick> <KeyFrameSet>

  97. Transition constraintSetStart constraintSetEnd motionInterpolator duration <OnSwipe> <OnClick> <KeyFrameSet>

  98. @xml/motion_poster.xml <MotionScene> <Transition android:id="@+id/transition_poster" app:constraintSetStart="@+id/frame_poster_top" app:constraintSetEnd=“@+id/frame_poster_middle" > </Transition> <ConstraintSet android:id="@+id/frame_poster_top">

    ••• </ConstraintSet> <ConstraintSet android:id="@+id/frame_poster_middle"> ••• </ConstraintSet> </MotionScene> Transition
  99. @xml/motion_poster.xml Transition <MotionScene> <Transition android:id=“@+id/transition_poster" app:constraintSetStart=“@+id/frame_poster_top" app:constraintSetEnd=“@+id/frame_poster_middle" > <OnClick app:clickAction="toggle"

    app:targetId=“@+id/card_movie_poster"/> </Transition> <ConstraintSet android:id="@+id/frame_poster_top"> ••• </ConstraintSet> <ConstraintSet android:id="@+id/frame_poster_middle"> ••• </ConstraintSet> </MotionScene>
  100. Movie Poster ✔ @layout/layout_poster.xml @xml/motion_poster.xml

  101. Movie Poster ✔ ✔ @layout/layout_poster.xml @xml/motion_poster.xml

  102. Yay !!! First Version Done

  103. Movie Poster + Movie Information Card Add CardView to layout_poster.xml

    Modify motion_poster.xml ⚠ Poster’s elevation changed
  104. layout_poster.xml

  105. <androidx.constraintlayout.motion.widget.MotionLayout android:layout_width="match_parent" android:layout_height="match_parent" app:layoutDescription="@xml/motion_poster"> <com.google.android.material.card.MaterialCardView android:id="@+id/card_movie_poster"> <ImageView android:id=“@+id/image_poster" ••• />

    </com.google.android.material.card.MaterialCardView> <androidx.constraintlayout.widget.Guideline android:id=“@+id/guide_x_10” ••• /> <androidx.constraintlayout.widget.Guideline android:id=“@+id/guide_y_52" ••• /> <androidx.constraintlayout.widget.Guideline android:id=“@+id/guide_y_48” ••• /> </androidx.constraintlayout.motion.widget.MotionLayout> @layout/layout_poster.xml
  106. <com.google.android.material.card.MaterialCardView android:id="@+id/card_movie_poster"> <ImageView android:id=“@+id/image_poster" ••• /> </com.google.android.material.card.MaterialCardView> <androidx.constraintlayout.widget.Guideline android:id=“@+id/guide_x_10” •••

    /> <androidx.constraintlayout.widget.Guideline android:id=“@+id/guide_y_52" ••• /> <androidx.constraintlayout.widget.Guideline android:id=“@+id/guide_y_48” ••• /> <com.google.android.material.card.MaterialCardView android:id="@+id/card_movie_info" android:layout_width="0dp" android:layout_height="0dp" app:cardElevation="4dp" app:layout_constraintDimensionRatio=“1:1" /> </androidx.constraintlayout.motion.widget.MotionLayout> @layout/layout_poster.xml
  107. layout_poster.xml

  108. Movie Poster + Movie Information Card Add CardView to layout_poster.xml

    Modify @xml/motion_poster.xml ✔
  109. @xml/motion_poster.xml

  110. Start State @xml/motion_poster.xml <MotionScene> <ConstraintSet android:id="@+id/frame_poster_top"> <Constraint android:id="@+id/card_movie_poster"> ••• </Constraint>

    </ConstraintSet> </MotionScene>
  111. Start State @xml/motion_poster.xml <MotionScene> <ConstraintSet android:id="@+id/frame_poster_top"> <Constraint android:id="@+id/card_movie_poster"> ••• </Constraint>

    </ConstraintSet> </MotionScene>
  112. Start State @xml/motion_poster.xml <MotionScene> <ConstraintSet android:id="@+id/frame_poster_top"> <Constraint android:id="@+id/card_movie_poster"> ••• <CustomAttribute

    app:attributeName="cardElevation" app:customDimension=“16dp" /> </Constraint> </ConstraintSet> </MotionScene>
  113. <MotionScene> <ConstraintSet android:id="@+id/frame_poster_top"> <Constraint android:id="@+id/card_movie_poster"> ••• <CustomAttribute app:attributeName="cardElevation" app:customDimension=“16dp" />

    </Constraint> <Constraint android:id=“@+id/card_movie_info"> </Constraint> </ConstraintSet> </MotionScene> Start State @xml/motion_poster.xml
  114. <ConstraintSet android:id="@+id/frame_poster_top"> <Constraint android:id="@+id/card_movie_poster"> <CustomAttribute app:attributeName="cardElevation" app:customDimension=“16dp" /> </Constraint> <Constraint

    android:id=“@+id/card_movie_info"> <Layout android:layout_width="match_parent" android:layout_height=“0dp" android:layout_marginTop="48dp" app:layout_constraintTop_toBottomOf=“@+id/guide_x_10” app:layout_constraintBottom_toBottomOf=“parent" /> </Constraint> </ConstraintSet> </MotionScene> Start State @xml/motion_poster.xml
  115. @xml/motion_poster.xml Start State End State

  116. <MotionScene> <ConstraintSet android:id=“@+id/frame_poster_top”> ••• </ConstraintSet> <ConstraintSet android:id="@+id/frame_poster_middle"> <Constraint android:id="@+id/card_movie_poster"> •••

    </Constraint> </ConstraintSet> </MotionScene> End State @xml/motion_poster.xml
  117. <MotionScene> <ConstraintSet android:id=“@+id/frame_poster_top”> ••• </ConstraintSet> <ConstraintSet android:id="@+id/frame_poster_middle"> <Constraint android:id="@+id/card_movie_poster"> •••

    </Constraint> </ConstraintSet> </MotionScene> End State @xml/motion_poster.xml
  118. <MotionScene> <ConstraintSet android:id=“@+id/frame_poster_top”> ••• </ConstraintSet> <ConstraintSet android:id="@+id/frame_poster_middle"> <Constraint android:id="@+id/card_movie_poster"> •••

    <CustomAttribute app:attributeName="cardElevation" app:customDimension=“2dp" /> </Constraint> </ConstraintSet> </MotionScene> End State @xml/motion_poster.xml
  119. <ConstraintSet android:id="@+id/frame_poster_middle"> <Constraint android:id="@+id/card_movie_poster"> ••• <CustomAttribute app:attributeName="cardElevation" app:customDimension=“2dp" /> </Constraint>

    <Constraint android:id=“@+id/card_movie_info"> </Constraint> </ConstraintSet> </MotionScene> End State @xml/motion_poster.xml
  120. ••• <CustomAttribute app:attributeName="cardElevation" app:customDimension=“2dp" /> </Constraint> <Constraint android:id=“@+id/card_movie_info"> <Layout android:layout_width="0dp"

    android:layout_height="0dp" android:layout_marginStart="24dp" app:layout_constraintDimensionRatio="1:1" app:layout_constraintEnd_toEndOf=“@+id/guide_y_52" app:layout_constraintStart_toStartOf=“parent" app:layout_constraintTop_toTopOf=“parent" app:layout_constraintBottom_toBottomOf="parent" /> </Constraint> </ConstraintSet> </MotionScene> End State @xml/motion_poster.xml
  121. @xml/motion_poster.xml Start State End State

  122. Movie Poster + Movie Information Card Add CardView to layout_poster.xml

    Modify @xml/motion_poster.xml ✔ ✔
  123. Movie Poster + Movie Information Card Expected Result

  124. Movie Poster + Movie Information Card Expected Result

  125. KeyFrames to the rescue

  126. KeyFrames Start End progress = 0 progress = 100

  127. KeyFrames Start End progress = 0 progress = 100 KeyFrame

    progress = 50
  128. KeyFrames Start End progress = 0 progress = 100 KeyFrame

    progress = 50 10 20 70
  129. KeyFrames <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle>

  130. KeyFrames <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle> Controls layout position during animation

  131. Controls layout position during animation <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle> KeyFrames

  132. KeyFrames <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle>

  133. KeyFrames <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle> Controls the post layout properties

    during animation
  134. KeyFrames <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle> Controls the post layout properties

    during animation
  135. KeyFrames <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle>

  136. KeyFrames <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle> Controls oscillations with respect to

    position of post layout properties during animation
  137. <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle> Controls oscillations with respect to position

    of post layout properties during animation KeyFrames
  138. KeyFrames <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle> Controls oscillations with respect to

    position of post layout properties during animation
  139. KeyFrames <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle>

  140. KeyFrames <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle> Controls oscillations with respect to

    time of post layout properties during animation
  141. KeyFrames <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle> Controls oscillations with respect to

    time of post layout properties during animation
  142. KeyFrames <KeyPosition> <KeyAttribute> <KeyCircle> <KeyTimeCircle> Controls oscillations with respect to

    time of post layout properties during animation
  143. Add KeyFrames for Poster

  144. Add KeyFrames for Poster @xml/motion_poster.xml <Transition android:id=“@+id/transition_poster" app:constraintSetStart=“@+id/frame_poster_top" app:constraintSetEnd=“@+id/frame_poster_middle" >

    <OnClick app:clickAction="toggle" app:targetId=“@+id/card_movie_poster"/> </Transition>
  145. Add KeyFrames for Poster @xml/motion_poster.xml <Transition android:id=“@+id/transition_poster" app:constraintSetStart=“@+id/frame_poster_top" app:constraintSetEnd=“@+id/frame_poster_middle" >

    <KeyFrameSet> </KeyFrameSet> <OnClick app:clickAction="toggle" app:targetId=“@+id/card_movie_poster"/> </Transition>
  146. <Transition android:id=“@+id/transition_poster" app:constraintSetStart=“@+id/frame_poster_top" app:constraintSetEnd=“@+id/frame_poster_middle" > <KeyFrameSet> <KeyPosition app:framePosition="90" app:keyPositionType="parentRelative" app:motionTarget="@+id/card_movie_poster"

    app:percentX="1" app:percentY=".5" /> </KeyFrameSet> <OnClick app:clickAction="toggle" app:targetId=“@+id/card_movie_poster"/> </Transition> Add KeyFrames for Poster @xml/motion_poster.xml
  147. Add KeyFrames for Poster @xml/motion_poster.xml <Transition android:id=“@+id/transition_poster" app:constraintSetStart=“@+id/frame_poster_top" app:constraintSetEnd=“@+id/frame_poster_middle" >

    <KeyFrameSet> <KeyPosition app:framePosition="90" app:keyPositionType="parentRelative" app:motionTarget="@+id/card_movie_poster" app:percentX="1" app:percentY=".5" /> <KeyPosition app:framePosition="90" app:keyPositionType="parentRelative" app:motionTarget="@+id/card_movie_info" app:percentY=".5" app:percentX="0" /> </KeyFrameSet> <OnClick app:clickAction="toggle" app:targetId=“@+id/card_movie_poster"/>
  148. Recap

  149. Recap <MotionScene> <Transition app:constraintSetEnd="@+id/frame_poster_middle" app:constraintSetStart="@+id/frame_poster_top" > ••• </Transition> <ConstraintSet android:id=“@+id/frame_poster_middle">

    ••• </ConstraintSet> <ConstraintSet android:id=“@+id/frame_poster_top"> ••• </ConstraintSet> </MotionScene>
  150. <MotionScene> <Transition app:constraintSetEnd="@+id/frame_poster_middle" app:constraintSetStart="@+id/frame_poster_top" > ••• </Transition> <ConstraintSet android:id=“@+id/frame_poster_middle"> •••

    </ConstraintSet> <ConstraintSet android:id=“@+id/frame_poster_top"> <Constraint android:id="@+id/card_movie_poster"> <Constraint android:id="@+id/card_movie_info"> </ConstraintSet> </MotionScene> Recap
  151. <MotionScene> <Transition app:constraintSetEnd="@+id/frame_poster_middle" app:constraintSetStart="@+id/frame_poster_top" > ••• </Transition> <ConstraintSet android:id=“@+id/frame_poster_middle"> •••

    </ConstraintSet> <ConstraintSet android:id=“@+id/frame_poster_top"> ••• </ConstraintSet> </MotionScene> Recap
  152. <MotionScene> <Transition app:constraintSetEnd="@+id/frame_poster_middle" app:constraintSetStart="@+id/frame_poster_top" > ••• </Transition> <ConstraintSet android:id=“@+id/frame_poster_middle"> <Constraint

    android:id="@+id/card_movie_poster"> <Constraint android:id="@+id/card_movie_info"> </ConstraintSet> <ConstraintSet android:id=“@+id/frame_poster_top"> ••• </ConstraintSet> </MotionScene> Recap
  153. <MotionScene> <Transition app:constraintSetEnd="@+id/frame_poster_middle" app:constraintSetStart="@+id/frame_poster_top" > ••• </Transition> <ConstraintSet android:id=“@+id/frame_poster_middle"> •••

    </ConstraintSet> <ConstraintSet android:id=“@+id/frame_poster_top"> ••• </ConstraintSet> </MotionScene> Recap
  154. <MotionScene> <Transition app:constraintSetEnd="@+id/frame_poster_middle" app:constraintSetStart="@+id/frame_poster_top" > <OnClick app:clickAction="toggle" app:targetId="@+id/card_movie_poster"/> ••• </Transition>

    <ConstraintSet android:id=“@+id/frame_poster_middle"> ••• </ConstraintSet> <ConstraintSet android:id=“@+id/frame_poster_top"> ••• </ConstraintSet> Recap
  155. <MotionScene> <Transition app:constraintSetEnd="@+id/frame_poster_middle" app:constraintSetStart="@+id/frame_poster_top" > <OnClick app:clickAction="toggle" app:targetId=“@+id/card_movie_poster"/> <KeyFrameSet> <KeyPosition

    app:framePosition="90" app:motionTarget="@+id/card_movie_poster" ••• /> <KeyPosition app:framePosition="90" app:motionTarget=“@+id/card_movie_info" ••• /> </KeyFrameSet> </Transition> <ConstraintSet android:id=“@+id/frame_poster_middle"> ••• Recap
  156. Movie Informations @layout/layout_movie_info.xml @motion/motion_movie_info.xml

  157. @layout/layout_movie_info.xml Holds 4 TextViews

  158. Movie Informations @layout/layout_movie_info.xml @motion/motion_movie_info.xml ✔

  159. @motion/motion_movie_info.xml Holds 2 ConstraintSets and Transition

  160. Movie Informations @layout/layout_movie_info.xml @motion/motion_movie_info.xml ✔ ✔ Use KeyFrames to show

    or hide movie summary at the middle
  161. Two Screens

  162. Combine Two Screens @layout/movie_poster.xml @layout/movie_info.xml

  163. Combine Two Screens <com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView> @layout/movie_poster.xml @layout/movie_info.xml

  164. Combine Two Screens <com.google.android.material.card.MaterialCardView> <include layout="@layout/layout_movie_info"/> </com.google.android.material.card.MaterialCardView> @layout/movie_poster.xml @layout/movie_info.xml

  165. motionLayoutPoster.setTransitionListener( ) Combine Two Screens Passing progress to child layout

    PosterActivity.kt
  166. motionLayoutPoster.setTransitionListener(object : TransitionListener { override fun onTransitionChange( motionLayout: MotionLayout?, startState:

    Int, endState: Int, progress: Float ) { } • • • }) Combine Two Screens Passing progress to child layout PosterActivity.kt
  167. motionLayoutPoster.setTransitionListener(object : TransitionListener { override fun onTransitionChange( motionLayout: MotionLayout?, startState:

    Int, endState: Int, progress: Float ) { } • • • }) Combine Two Screens Passing progress to child layout PosterActivity.kt
  168. motionLayoutPoster.setTransitionListener(object : TransitionListener { override fun onTransitionChange( motionLayout: MotionLayout?, startState:

    Int, endState: Int, progress: Float ) { motionLayoutMovieInfo.progress = progress } • • • }) Combine Two Screens Passing progress to child layout PosterActivity.kt
  169. After Combining Two Screens

  170. More Movies

  171. Card for More Movies Add CardView to layout_poster.xml + Modify

    motion_poster.xml
  172. Card for More Movies Start State End State

  173. Card for More Movies Start State End State

  174. <ConstraintSet android:id=“@+id/frame_poster_top"> <Constraint android:id="@+id/card_movie_poster"> ... </Constraint> <Constraint android:id="@+id/card_movie_info"> ... </Constraint>

    </ConstraintSet> @xml/motion_poster.xml Start State
  175. <ConstraintSet android:id=“@+id/frame_poster_top"> <Constraint android:id="@+id/card_movie_poster"> ... </Constraint> <Constraint android:id="@+id/card_movie_info"> ... </Constraint>

    </ConstraintSet> @xml/motion_poster.xml
  176. <ConstraintSet android:id="@+id/frame_poster_top"> <Constraint android:id="@+id/card_movie_poster"> ... </Constraint> <Constraint android:id="@+id/card_movie_info"> ... </Constraint>

    <Constraint android:id="@+id/card_more_movies"> <Layout android:layout_width="400dp" android:layout_height="128dp" app:layout_constraintTop_toTopOf=“@+id/guide_x_93" app:layout_constraintStart_toStartOf=“@+id/guide_y_60” /> </Constraint> </ConstraintSet> @xml/motion_poster.xml
  177. Card for More Movies Start State End State

  178. <ConstraintSet android:id=“@+id/frame_more_movies_expanded"> </ConstraintSet> @xml/motion_poster.xml End State

  179. <ConstraintSet app:deriveConstraintsFrom="@+id/frame_poster_top" android:id="@+id/frame_more_movies_expanded"> </ConstraintSet> @xml/motion_poster.xml End State

  180. <ConstraintSet app:deriveConstraintsFrom="@+id/frame_poster_top" android:id=“@+id/frame_more_movies_expanded"> <Constraint android:id="@+id/card_more_movies"> </Constraint> </ConstraintSet> @xml/motion_poster.xml End State

  181. <ConstraintSet app:deriveConstraintsFrom="@+id/frame_poster_top" android:id=“@+id/frame_more_movies_expanded"> <Constraint android:id="@+id/card_more_movies"> <Layout app:layout_constraintBottom_toBottomOf="parent" android:layout_width="match_parent" android:layout_height="224dp" />

    </Constraint> </ConstraintSet> @xml/motion_poster.xml End State
  182. <Transition android:id="@+id/transition_more_movies" app:constraintSetEnd="@+id/frame_more_movies_expanded" app:constraintSetStart=“@+id/frame_poster_top"> </Transition> @xml/motion_poster.xml End State

  183. <Transition android:id="@+id/transition_more_movies" app:constraintSetEnd="@+id/frame_more_movies_expanded" app:constraintSetStart=“@+id/frame_poster_top"> <OnSwipe app:dragDirection="dragUp" app:touchRegionId="@+id/card_more_movies" app:touchAnchorId=“@+id/card_more_movies"/> </Transition> @xml/motion_poster.xml

    Transition
  184. Card for More Movies

  185. Add CardView to layout_poster.xml + Modify motion_poster.xml Card for More

    Movies ✔
  186. Add CardView to layout_poster.xml + Modify motion_poster.xml Card for More

    Movies ✔ Also add a view with opacity transition for background dimming
  187. More Movies @layout/layout_more_movies.xml @motion/motion_more_movies.xml

  188. @layout/layout_more_movies.xml <ImageView android:id=“@+id/image_arrow” •••/> <TextView android:id=“@+id/text_more_movies" ••• /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_more_movies"

    ••• />
  189. More Movies @layout/layout_more_movies.xml @motion/motion_more_movies.xml ✔

  190. @motion/motion_more_movies.xml more_movies_expanded [ End State ]

  191. @motion/motion_more_movies.xml more_movies_collapsed more_movies_expanded <MotionScene> <Transition android:id="@+id/transition" /> <ConstraintSet android:id="@+id/more_movies_collapsed" />

    <ConstraintSet android:id="@+id/more_movies_expanded" /> </MotionScene> [ End State ] [ Start State ]
  192. More Movies @layout/layout_more_movies.xml @motion/motion_more_movies.xml ✔ ✔

  193. Combine More Movies to UI @layout/layout_poster.xml @layout/layout_more_movies.xml

  194. Combine more movies @layout/layout_poster.xml <com.google.android.material.card.MaterialCardView android:id="@+id/card_more_movies" > <include layout=“@layout/layout_more_movies"/> </com.google.android.material.card.MaterialCardView>

  195. motionLayoutPoster.setTransitionListener(object : TransitionListener { override fun onTransitionChange( motionLayout: MotionLayout?, startState:

    Int, endState: Int, progress: Float ) { • • • if(motionLayout?.startState == R.id.frame_poster_top && motionLayout.endState == R.id.frame_more_movies_expanded){ } } • • • }) Combine more movies Passing progress to child layout PosterActivity.kt
  196. motionLayoutPoster.setTransitionListener(object : TransitionListener { override fun onTransitionChange( motionLayout: MotionLayout?, startState:

    Int, endState: Int, progress: Float ) { • • • if(motionLayout?.startState == R.id.frame_poster_top && motionLayout.endState == R.id.frame_more_movies_expanded){ motion_layout_more_movies.progress = progress } } • • • }) Combine more movies Passing progress to child layout PosterActivity.kt
  197. Finished : More Movies

  198. Recap @layout/layout_movie_info.xml @xml/motion_movie_info.xml @layout/layout_more_movies.xml @xml/motion_more_movies.xml @layout/layout_poster.xml @xml/motion_poster.xml

  199. @layout/layout_movie_info.xml @xml/motion_movie_info.xml @layout/layout_more_movies.xml @xml/motion_more_movies.xml @layout/layout_poster.xml @xml/motion_poster.xml Recap

  200. @layout/layout_movie_info.xml @xml/motion_movie_info.xml @layout/layout_more_movies.xml @xml/motion_more_movies.xml @layout/layout_poster.xml @xml/motion_poster.xml Recap

  201. @xml/motion_poster.xml Transition Transition State State State

  202. None
  203. Some Examples By @chrisbanes

  204. Some Examples By @johnhoford

  205. Some Examples By @MikeScamell

  206. Tips #1 Debugging Motion Layout

  207. Tips #1 Debugging Motion Layout

  208. Tips #2 Slow down transition

  209. Tips #2 Slow down transition

  210. Tips #3 Programatic API

  211. Tips #3 Programatic API https://developer.android.com/reference/android/support/constraint/ motion/MotionLayout.html#public-methods

  212. 1. Learn Constraint Layout 2. Find UI inspiration 3. Make

    experiments with Motion Layout 4. Draw your own design [ Optional ] 5. Add transitions [ Optional ] Steps to learn Motion Layout Figma Adobe XD Adobe XD
  213. Add Motion Layout to the app androidx.constraintlayout:constraintlayout:2.0.0-beta2

  214. 1. Define frames, UI components 2. Define motions 3. Collaborate

    with designers 4. Implement 5. Polish Add Motion Layout to the app
  215. 1. Collapsing Toolbar Refactor existing animation to Motion Layout

  216. 1. Collapsing Toolbar 2. ViewPager Refactor existing animation to Motion

    Layout
  217. 1. Collapsing Toolbar 2. ViewPager 3. Gesture based transitions Refactor

    existing animation to Motion Layout
  218. 1. Collapsing Toolbar 2. ViewPager 3. Gesture based transitions 4.

    Navigation view with
 custom behaviors Refactor existing animation to Motion Layout
  219. 1. Collapsing Toolbar 2. ViewPager 3. Gesture based transitions 4.

    Navigation view with
 custom behaviors 5. Progress based views Refactor existing animation to Motion Layout
  220. The Future Motion Layout Editor In Development

  221. Introduction to MotionLayout series https:/ /medium.com/google-developers/introduction-to-motionlayout-part- i-29208674b10d Official Docs https:/

    /developer.android.com/reference/android/support/constraint/motion/ MotionLayout What’s new in ConstraintLayout https:/ /www.youtube.com/watch?v=29gLA90m6Gk Official Samples on Github https:/ /github.com/googlesamples/android-ConstraintLayoutExamples Learning Resources
  222. Constraint Layout Guide https:/ /constraintlayout.com Twitter #motionlayout https:/ /twitter.com/search?q=%23motionlayout Optimizing

    UIs using Constraint Layout (Google I/O extended 2018) https:/ /speakerdeck.com/hashlin/optimizing-uis-using-constraint-layout Source codes for this talk https:/ /github.com/hashlin/DroidYangonMoviesApp Learning Resources Cont’d
  223. Motion Layout : Make your apps move auto-magically Q &

    A @Linminphyoe1