Motion Layout is introduced in ConstraintLayout 2.0 and it gives a lot of flexibility to make animations and transitions.
Motion Layout :Make your apps move auto-magically@Linminphyoe1
View Slide
About the talk• A walkthrough to sample app• Strategy for building aninteractive animations easily• Learning approaches to Motion Layout• Tips and tricks
Who am I ?Lin Min PhyoSenior Android DeveloperProduct, UI/UX, Software Architectures
Motion LayoutMake your apps move auto-magically
Motion Layoutclass MotionLayout extends ConstraintLayout
Back to the past
Before Constraint LayoutBuilding UI is hard
• Nested Hierarchy• Non-functional DesignView• Not FlexibleBefore Constraint Layout
Constraint Layout 1.xWhich problems are solved?
Constraint Layout 1.xFlatter Hierarchy
Constraint Layout 1.x• Easy positioning views• Guidelines• Chains• Bias• Many utilities andfunctionalitiesFeatures Highlightshttps://developer.android.com/reference/android/support/constraint/ConstraintLayout
Constraint Layout 1.xHow?
Constraint Layout 1.x• Connections between views• Connections between viewand parent view group• Connections between viewand helper viewsConstraints
ConstraintsA
ConstraintsA B
Constraintsapp:layout_constraintStart_toEndOf=“@+id/A” />A B
ConstraintsBA
ConstraintsABapp:layout_constraintStart_toStartOf=“@+id/A” />
Constraintsapp:layout_constraintStart_toStartOf=“parent” />B
Constraints
Guidelinesandroid:layout_width="wrap_content"android:layout_height=“wrap_content”/>
Guidelinesandroid:layout_width="wrap_content"android:layout_height=“wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent=“.30”/>
Guidelinesandroid:layout_width="wrap_content"android:layout_height=“wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent=“.60”/>
Guidelinesandroid:layout_width="wrap_content"android:layout_height=“wrap_content"android:orientation=“horizontal"app:layout_constraintGuide_percent=“.40”/>
TransitionsHow transitions work
How transitions work
Start State End StateTransitionHow transitions work
How transitions workStart State End StateTransition
Constraint SetsMade animation easy
state_one.xmlConstraint Sets
state_one.xml state_two.xmlConstraint Sets
Constraint SetsActivity.kt
Constraint SetsConstraintSet constraintSet1 = new ConstraintSet();ConstraintSet constraintSet2 = new ConstraintSet();Activity.kt
Constraint SetsConstraintSet constraintSet1 = new ConstraintSet();ConstraintSet constraintSet2 = new ConstraintSet();constraintSet1.clone(context, R.layout.state_one);constraintSet2.clone(context, R.layout.state_two);Activity.kt
Constraint SetsConstraintSet 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
Constraint SetsConstraintSet 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
Constraint Layout 2.xMore goodness
Constraint Layout 2.x• Linear helper• Flow• ImageFilterView• Layer• Mock View• Decorators• Motion LayoutOfficial docs @ https://developer.android.com/reference/android/support/constraint/classes
Motion LayoutOne layout to rule them all
@layout/state_one.xml@layout/state_two.xmlpackage/activity.ktConstraint Sets Motion Layout@layout/layout.xmlVS
@layout/state_one.xml@layout/state_two.xmlpackage/activity.ktConstraint Sets Motion Layout@layout/layout.xmlVSViews of the layout
@layout/state_one.xml@layout/state_two.xmlpackage/activity.ktConstraint Sets Motion Layout@layout/layout.xml@xml/motion.xmlVSView attributes and transitions
@layout/state_one.xml@layout/state_two.xmlpackage/activity.ktConstraint Sets Motion Layout@layout/layout.xml@layout/motion.xmlpackage/activity.ktVS[ Optional ]
Sample App
Movie Poster@layout/layout_poster.xml@xml/motion_poster.xml
android:layout_width="match_parent"android:layout_height="match_parent"app:layoutDescription="@xml/motion_poster">@layout/layout_poster.xml
android:layout_width="match_parent"android:layout_height="match_parent"app:layoutDescription="@xml/motion_poster">android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/card_movie_poster"app:layout_constraintDimensionRatio="2:3">android:id="@+id/image_poster"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="centerCrop"android:src="@drawable/poster_endgame"/>@layout/layout_poster.xml
android:layout_height="match_parent"android:scaleType="centerCrop"android:src="@drawable/poster_endgame"/>android:id="@+id/guideline_horizontal_10"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"app:layout_constraintGuide_percent=".10"/>android:id="@+id/guideline_vertical_52"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent=".52"/>android:id="@+id/guideline_vertical_48"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent=“.48"/>@layout/layout_poster.xml
Movie Poster✔@layout/layout_poster.xml@xml/motion_poster.xml
@xml/motion_poster.xml
@xml/motion_poster.xmlStart State End StateTransition
Start State@xml/motion_poster.xml
MotionSceneXML for holding views’ attributes and transitions
MotionScene (Optional)
MotionScene (Optional)Hold view attributes
MotionScene (Optional)Define start frame, end frame and transition information
MotionScene (Optional)Group of states defined for different screens
Start State@xml/motion_poster.xmlandroid:id="@+id/frame_poster_top">
ConstraintsAttributes of a view
Constraint AttributesLayoutTransformPropertyMotionCustomAttribute
Constraint AttributesLayoutTransformPropertyMotionCustomAttributeView Positioning Attributes
Constraint AttributesLayoutTransformPropertyMotionCustomAttributeRotations, re-sizings, translation
Constraint AttributesLayoutTransformPropertyMotionCustomAttributeAlpha, Visibility
Constraint AttributesLayoutTransformPropertyMotionCustomAttributePath Rotation, Easing
Constraint AttributesLayoutTransformPropertyMotionCustomAttributeView attributes with reflection
Start State@xml/motion_poster.xmlandroid:id="@+id/frame_poster_top">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”/>
android:id=“@+id/frame_poster_top">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”/>End State@xml/motion_poster.xml
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”/>End State@xml/motion_poster.xml
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”/>End State@xml/motion_poster.xml
app:layout_constraintStart_toStartOf=“parent"app:layout_constraintEnd_toStartOf=“@+id/guide_y_52"app:layout_constraintTop_toTopOf=“@+id/guide_x_10”/>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"/>End State@xml/motion_poster.xml
Start State End StateTransition@xml/motion_poster.xml
Transition@xml/motion_poster.xml••••••
@xml/motion_poster.xmlandroid:id=“@+id/transition_poster"app:constraintSetStart="@+id/frame_poster_top"app:constraintSetEnd=“@+id/frame_poster_middle" >••••••Transition
TransitionDescribe start frame, end frame and transitioninformations
TransitionconstraintSetStartconstraintSetEndmotionInterpolatorduration
TransitionconstraintSetStartconstraintSetEndmotionInterpolatordurationTransition easing
@xml/motion_poster.xmlandroid:id="@+id/transition_poster"app:constraintSetStart="@+id/frame_poster_top"app:constraintSetEnd=“@+id/frame_poster_middle" >••••••Transition
@xml/motion_poster.xmlTransitionandroid:id=“@+id/transition_poster"app:constraintSetStart=“@+id/frame_poster_top"app:constraintSetEnd=“@+id/frame_poster_middle" >app:clickAction="toggle"app:targetId=“@+id/card_movie_poster"/>••••••
Movie Poster✔✔@layout/layout_poster.xml@xml/motion_poster.xml
Yay !!!First Version Done
Movie Poster + Movie Information CardAdd CardView to layout_poster.xmlModify motion_poster.xml⚠ Poster’s elevation changed
layout_poster.xml
android:layout_width="match_parent"android:layout_height="match_parent"app:layoutDescription="@xml/motion_poster">android:id="@+id/card_movie_poster">android:id=“@+id/guide_x_10” ••• />android:id=“@+id/guide_y_52" ••• />android:id=“@+id/guide_y_48” ••• />@layout/layout_poster.xml
android:id="@+id/card_movie_poster">android:id=“@+id/guide_x_10” ••• />android:id=“@+id/guide_y_52" ••• />android:id=“@+id/guide_y_48” ••• />android:id="@+id/card_movie_info"android:layout_width="0dp"android:layout_height="0dp"app:cardElevation="4dp"app:layout_constraintDimensionRatio=“1:1"/>@layout/layout_poster.xml
Movie Poster + Movie Information CardAdd CardView to layout_poster.xmlModify @xml/motion_poster.xml✔
Start State@xml/motion_poster.xml•••
Start State@xml/motion_poster.xml•••app:attributeName="cardElevation"app:customDimension=“16dp" />
•••app:attributeName="cardElevation"app:customDimension=“16dp" />Start State@xml/motion_poster.xml
app:attributeName="cardElevation"app:customDimension=“16dp" />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" />Start State@xml/motion_poster.xml
@xml/motion_poster.xmlStart State End State
••••••End State@xml/motion_poster.xml
••••••app:attributeName="cardElevation"app:customDimension=“2dp" />End State@xml/motion_poster.xml
•••app:attributeName="cardElevation"app:customDimension=“2dp" />End State@xml/motion_poster.xml
•••app:attributeName="cardElevation"app:customDimension=“2dp" />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"/>End State@xml/motion_poster.xml
Movie Poster + Movie Information CardAdd CardView to layout_poster.xmlModify @xml/motion_poster.xml✔✔
Movie Poster + Movie Information CardExpected Result
KeyFrames to the rescue
KeyFramesStart Endprogress = 0 progress = 100
KeyFramesStart Endprogress = 0 progress = 100KeyFrameprogress = 50
KeyFramesStart Endprogress = 0 progress = 100KeyFrameprogress = 5010 20 70
KeyFrames
KeyFramesControls layout position during animation
Controls layout position during animationKeyFrames
KeyFramesControls the post layout properties during animation
KeyFramesControls oscillations with respect to position of postlayout properties during animation
Controls oscillations with respect to position of postlayout properties during animationKeyFrames
KeyFramesControls oscillations with respect to time of post layoutproperties during animation
Add KeyFrames for Poster
Add KeyFrames for Poster@xml/motion_poster.xmlandroid:id=“@+id/transition_poster"app:constraintSetStart=“@+id/frame_poster_top"app:constraintSetEnd=“@+id/frame_poster_middle" >app:clickAction="toggle"app:targetId=“@+id/card_movie_poster"/>
android:id=“@+id/transition_poster"app:constraintSetStart=“@+id/frame_poster_top"app:constraintSetEnd=“@+id/frame_poster_middle" >app:framePosition="90"app:keyPositionType="parentRelative"app:motionTarget="@+id/card_movie_poster"app:percentX="1"app:percentY=".5" />app:clickAction="toggle"app:targetId=“@+id/card_movie_poster"/>Add KeyFrames for Poster@xml/motion_poster.xml
Add KeyFrames for Poster@xml/motion_poster.xmlandroid:id=“@+id/transition_poster"app:constraintSetStart=“@+id/frame_poster_top"app:constraintSetEnd=“@+id/frame_poster_middle" >app:framePosition="90"app:keyPositionType="parentRelative"app:motionTarget="@+id/card_movie_poster"app:percentX="1"app:percentY=".5" />app:framePosition="90"app:keyPositionType="parentRelative"app:motionTarget="@+id/card_movie_info"app:percentY=".5"app:percentX="0" />app:clickAction="toggle"app:targetId=“@+id/card_movie_poster"/>
Recap
Recapapp:constraintSetEnd="@+id/frame_poster_middle"app:constraintSetStart="@+id/frame_poster_top" >•••••••••
app:constraintSetEnd="@+id/frame_poster_middle"app:constraintSetStart="@+id/frame_poster_top" >••••••Recap
app:constraintSetEnd="@+id/frame_poster_middle"app:constraintSetStart="@+id/frame_poster_top" >•••••••••Recap
app:constraintSetEnd="@+id/frame_poster_middle"app:constraintSetStart="@+id/frame_poster_top" >app:clickAction="toggle"app:targetId="@+id/card_movie_poster"/>•••••••••Recap
app:constraintSetEnd="@+id/frame_poster_middle"app:constraintSetStart="@+id/frame_poster_top" >app:clickAction="toggle"app:targetId=“@+id/card_movie_poster"/>app:framePosition="90"app:motionTarget="@+id/card_movie_poster" ••• />app:framePosition="90"app:motionTarget=“@+id/card_movie_info" ••• />•••Recap
Movie Informations@layout/layout_movie_info.xml@motion/motion_movie_info.xml
@layout/layout_movie_info.xmlHolds 4 TextViews
Movie Informations@layout/layout_movie_info.xml@motion/motion_movie_info.xml✔
@motion/motion_movie_info.xmlHolds 2 ConstraintSets and Transition
Movie Informations@layout/layout_movie_info.xml@motion/motion_movie_info.xml✔✔Use KeyFrames to show or hidemovie summary at the middle
Two Screens
Combine Two Screens@layout/movie_poster.xml @layout/movie_info.xml
motionLayoutPoster.setTransitionListener( )Combine Two ScreensPassing progress to child layoutPosterActivity.kt
motionLayoutPoster.setTransitionListener(object : TransitionListener {override fun onTransitionChange(motionLayout: MotionLayout?,startState: Int,endState: Int,progress: Float) {}• • •})Combine Two ScreensPassing progress to child layoutPosterActivity.kt
motionLayoutPoster.setTransitionListener(object : TransitionListener {override fun onTransitionChange(motionLayout: MotionLayout?,startState: Int,endState: Int,progress: Float) {motionLayoutMovieInfo.progress = progress}• • •})Combine Two ScreensPassing progress to child layoutPosterActivity.kt
After Combining Two Screens
More Movies
Card for More MoviesAdd CardView to layout_poster.xml+ Modify motion_poster.xml
Card for More MoviesStart State End State
android:id=“@+id/frame_poster_top">......@xml/motion_poster.xmlStart State
android:id=“@+id/frame_poster_top">......@xml/motion_poster.xml
android:id="@+id/frame_poster_top">......android:layout_width="400dp"android:layout_height="128dp"app:layout_constraintTop_toTopOf=“@+id/guide_x_93"app:layout_constraintStart_toStartOf=“@+id/guide_y_60”/>@xml/motion_poster.xml
android:id=“@+id/frame_more_movies_expanded">@xml/motion_poster.xmlEnd State
app:deriveConstraintsFrom="@+id/frame_poster_top"android:id="@+id/frame_more_movies_expanded">@xml/motion_poster.xmlEnd State
app:deriveConstraintsFrom="@+id/frame_poster_top"android:id=“@+id/frame_more_movies_expanded">@xml/motion_poster.xmlEnd State
app:deriveConstraintsFrom="@+id/frame_poster_top"android:id=“@+id/frame_more_movies_expanded">app:layout_constraintBottom_toBottomOf="parent"android:layout_width="match_parent"android:layout_height="224dp"/>@xml/motion_poster.xmlEnd State
android:id="@+id/transition_more_movies"app:constraintSetEnd="@+id/frame_more_movies_expanded"app:constraintSetStart=“@+id/frame_poster_top">@xml/motion_poster.xmlEnd State
android:id="@+id/transition_more_movies"app:constraintSetEnd="@+id/frame_more_movies_expanded"app:constraintSetStart=“@+id/frame_poster_top">app:dragDirection="dragUp"app:touchRegionId="@+id/card_more_movies"app:touchAnchorId=“@+id/card_more_movies"/>@xml/motion_poster.xmlTransition
Card for More Movies
Add CardView to layout_poster.xml+ Modify motion_poster.xmlCard for More Movies✔
Add CardView to layout_poster.xml+ Modify motion_poster.xmlCard for More Movies✔Also add a view withopacity transitionfor background dimming
More Movies@layout/layout_more_movies.xml@motion/motion_more_movies.xml
@layout/layout_more_movies.xml•••/>••• />android:id="@+id/rv_more_movies"••• />
More Movies@layout/layout_more_movies.xml@motion/motion_more_movies.xml✔
@motion/motion_more_movies.xmlmore_movies_expanded[ End State ]
@motion/motion_more_movies.xmlmore_movies_collapsedmore_movies_expandedandroid:id="@+id/transition" />android:id="@+id/more_movies_collapsed" />android:id="@+id/more_movies_expanded" />[ End State ][ Start State ]
More Movies@layout/layout_more_movies.xml@motion/motion_more_movies.xml✔✔
Combine More Movies to UI@layout/layout_poster.xml @layout/layout_more_movies.xml
Combine more movies@layout/layout_poster.xmlandroid:id="@+id/card_more_movies" >
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 moviesPassing progress to child layoutPosterActivity.kt
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 moviesPassing progress to child layoutPosterActivity.kt
Finished : More Movies
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
@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.xmlRecap
@xml/motion_poster.xmlTransition TransitionState State State
Some ExamplesBy @chrisbanes
Some ExamplesBy @johnhoford
Some ExamplesBy @MikeScamell
Tips #1Debugging Motion Layout
Tips #2Slow down transition
Tips #3Programatic API
Tips #3Programatic APIhttps://developer.android.com/reference/android/support/constraint/motion/MotionLayout.html#public-methods
1. Learn Constraint Layout2. Find UI inspiration3. Make experiments with Motion Layout4. Draw your own design [ Optional ]5. Add transitions [ Optional ]Steps to learn Motion LayoutFigma Adobe XDAdobe XD
Add Motion Layout to the appandroidx.constraintlayout:constraintlayout:2.0.0-beta2
1. Define frames, UI components2. Define motions3. Collaborate with designers4. Implement5. PolishAdd Motion Layout to the app
1. Collapsing ToolbarRefactor existing animation to Motion Layout
1. Collapsing Toolbar2. ViewPagerRefactor existing animation to Motion Layout
1. Collapsing Toolbar2. ViewPager3. Gesture based transitionsRefactor existing animation to Motion Layout
1. Collapsing Toolbar2. ViewPager3. Gesture based transitions4. Navigation view with custom behaviorsRefactor existing animation to Motion Layout
1. Collapsing Toolbar2. ViewPager3. Gesture based transitions4. Navigation view with custom behaviors5. Progress based viewsRefactor existing animation to Motion Layout
The FutureMotion Layout Editor In Development
Introduction to MotionLayout serieshttps://medium.com/google-developers/introduction-to-motionlayout-part-i-29208674b10dOfficial Docshttps://developer.android.com/reference/android/support/constraint/motion/MotionLayoutWhat’s new in ConstraintLayouthttps://www.youtube.com/watch?v=29gLA90m6GkOfficial Samples on Githubhttps://github.com/googlesamples/android-ConstraintLayoutExamplesLearning Resources
Constraint Layout Guidehttps://constraintlayout.comTwitter #motionlayouthttps://twitter.com/search?q=%23motionlayoutOptimizing UIs using Constraint Layout (Google I/O extended 2018)https://speakerdeck.com/hashlin/optimizing-uis-using-constraint-layoutSource codes for this talkhttps://github.com/hashlin/DroidYangonMoviesAppLearning Resources Cont’d
Motion Layout :Make your apps move auto-magicallyQ & A@Linminphyoe1