SlideShare a Scribd company logo
@mikescamell
Do the Loco-MotionLayout
@mikescamell
HERE!!!
@mikescamell
by Nikita Duhovny 
– Nicolas Roard
“A mix between the property animation framework, layout transitions
with TransitionManager, and CoordinatorLayout”
MotionLayout
@mikescamellScene 1 - Part 1
@mikescamellScene 1 - Part 1
<ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/bookCover"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:elevation="4dp"
android:outlineProvider="bounds"
android:src="@drawable/nolongerhuman"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3" />
</ConstraintLayout>
@mikescamellScene 1 - Part 1
@mikescamell
(Yes yes yes I know!)
dependencies {
  implementation 'com.android.support.constraint:constraint-layout:2.0.0-alpha3'
}
@mikescamellScene 1 - Part 2
<ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/bookCover"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:elevation="4dp"
android:outlineProvider="bounds"
android:src="@drawable/nolongerhuman"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3" />
</ConstraintLayout>
@mikescamellScene 1 - Part 2
<MotionLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/bookCover"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:elevation="4dp"
android:outlineProvider="bounds"
android:src="@drawable/nolongerhuman"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3" />
</MotionLayout>
@mikescamell
2019-03-20 19:45:26.529 28239-28239/? E/MotionLayout: WARNING NO app:layoutDescription tag
2019-03-20 19:45:26.683 28239-28239/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mikescamell.locomotionlayout, PID: 28239
java.lang.NullPointerException: Attempt to invoke virtual method 'int
androidx.constraintlayout.motion.widget.MotionScene.getDuration()' on a null object
reference
Scene 1 - Part 2
@mikescamell
@mikescamellScene 1 - Part 2
<MotionScene>
</MotionScene>
@mikescamellScene 1 - Part 2
<MotionScene>
<Transition
android:id="@+id/startToEnd"
app:constraintSetStart="@+id/start"
app:constraintSetEnd="@+id/end">
</Transition>
</MotionScene>
@mikescamell
<MotionScene>
<Transition
android:id="@+id/startToEnd"
app:constraintSetStart="@+id/start"
app:constraintSetEnd="@+id/end">
<OnSwipe
app:dragDirection="dragDown"
app:touchAnchorId="@id/bookCover"
app:touchAnchorSide="bottom" />
</Transition>
</MotionScene>
Scene 1 - Part 2
@mikescamellScene 1 - Part 2
@mikescamellScene 1 - Part 2
<MotionScene>
<Transition
android:id="@+id/startToEnd"
app:constraintSetStart="@+id/start"
app:constraintSetEnd="@+id/end">
<OnSwipe
app:dragDirection="dragDown"
app:touchAnchorId="@id/bookCover"
app:touchAnchorSide="bottom" />
</Transition>
</MotionScene>
@mikescamell
<MotionScene>
...
</MotionScene>
Scene 1 - Part 2
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/start">
</ConstraintSet>
</MotionScene>
Scene 1 - Part 2
@mikescamellScene 1 - Part 2
<MotionScene>
...
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookCover">
<Layout
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3"
app:layout_height="300dp"
app:layout_width="wrap_content" />
<Transform
app:rotationX="0"
app:translationY="0dp" />
</Constraint>
</ConstraintSet>
…
</MotionScene>
@mikescamellScene 1 - Part 2
<MotionScene>
...
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookCover">
<Layout
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3"
app:layout_height="300dp"
app:layout_width="wrap_content" />
<Transform
app:rotationX="0"
app:translationY="0dp" />
</Constraint>
</ConstraintSet>
</MotionScene>
@mikescamellScene 1 - Part 2
<MotionScene>
...
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookCover">
<Layout
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3"
app:layout_height="300dp"
app:layout_width="wrap_content" />
<Transform
app:rotationX="0"
app:translationY="0dp" />
</Constraint>
</ConstraintSet>
</MotionScene>
@mikescamellScene 1 - Part 2
<MotionScene>
...
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookCover">
<Layout
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3"
app:layout_height="300dp"
app:layout_width="wrap_content" />
<Transform
app:rotationX="0"
app:translationY="0dp" />
</Constraint>
</ConstraintSet>
</MotionScene>
@mikescamellScene 1 - Part 2
<MotionScene>
...
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookCover">
<Transform
app:rotationX="0"
app:translationY="0dp" />
</Constraint>
</ConstraintSet>
</MotionScene>
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/bookCover">
<Layout
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf=“parent"
app:layout_height="wrap_content"
app:layout_width="150dp" />
<Transform
app:rotationX="-55">
</Constraint>
</ConstraintSet>
</MotionScene>
Scene 1 - Part 2
@mikescamellScene 1 - Part 2
@mikescamellScene 1 - Part 3
@mikescamellScene 1 - Part 3
<MotionLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/scene1_part3">
<ImageView
android:id="@+id/bookCover"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:contentDescription="@string/bookcover"
android:elevation="4dp"
android:src="@drawable/nolongerhuman" />
</MotionLayout>
@mikescamell
<MotionLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/scene1_part3">
<MaterialCardView
android:id="@+id/bookSynopsisCard"
android:layout_width="140dp"
android:layout_height="140dp"
app:cardBackgroundColor="@color/crazyPink"
app:cardCornerRadius=“16dp" />
<ImageView … />
</MotionLayout>
Scene 1 - Part 3
@mikescamell
<MotionScene>
…
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.35"
app:layout_height="140dp"
app:layout_width="140dp" />
<Transform app:rotationX="-55" />
</Constraint>
…
</ConstraintSet>
…
</MotionScene>
Scene 1 - Part 3
@mikescamell
<MotionScene>
…
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.35"
app:layout_height="140dp"
app:layout_width="140dp" />
<Transform app:rotationX="-55" />
</Constraint>
…
</ConstraintSet>
…
</MotionScene>
Scene 1 - Part 3
@mikescamell
<MotionScene>
…
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.35"
app:layout_height="140dp"
app:layout_width="140dp" />
<Transform app:rotationX="-55" />
</Constraint>
…
</ConstraintSet>
…
</MotionScene>
Scene 1 - Part 3
@mikescamell
<MotionScene>
…
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3"
app:layout_height="300dp"
app:layout_width="300dp" />
<Transform app:rotationX="0" />
</Constraint>
…
</ConstraintSet>
</MotionScene>
Scene 1 - Part 3
@mikescamell
<MotionScene>
…
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3"
app:layout_height="300dp"
app:layout_width="300dp" />
<Transform app:rotationX="0" />
</Constraint>
…
</ConstraintSet>
</MotionScene>
Scene 1 - Part 3
@mikescamell
<MotionScene>
…
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3"
app:layout_height="300dp"
app:layout_width="300dp" />
<Transform app:rotationX="0" />
</Constraint>
…
</ConstraintSet>
</MotionScene>
Scene 1 - Part 3
@mikescamell
<MotionScene>
…
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/bookCover">
<Layout
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/bookSynopsisCard"
app:layout_height="wrap_content"
app:layout_width="150dp" />
<Transform
app:rotationX="-55"
app:translationY="-24dp" />
</Constraint>
</ConstraintSet>
</MotionScene>
Scene 1 - Part 3
@mikescamell
<MotionScene>
…
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/bookCover">
<Layout
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/bookSynopsisCard"
app:layout_height="wrap_content"
app:layout_width="150dp" />
<Transform
app:rotationX="-55"
app:translationY="-24dp" />
</Constraint>
</ConstraintSet>
</MotionScene>
Scene 1 - Part 3
@mikescamellScene 1 - Part 3
@mikescamellScene 1 - Part 3
@mikescamellScene 1 - Part 4
@mikescamellScene 1 - Part 4
@mikescamellScene 1 - Part 5
@mikescamellScene 1 - Part 6
@mikescamellScene 1 - Part 6
• KeyAttribute
• KeyPosition
• KeyCycle
• KeyTimeCycle
• KeyTrigger
KeyFrames
@mikescamell
<MotionScene>
<Transition ...>
<KeyFrameSet>
<KeyAttribute
android:alpha="0"
app:framePosition="70"
app:target="@id/bookSynopsisTitle" />
<KeyAttribute
android:alpha="0"
app:framePosition="70"
app:target="@id/bookSynopsisText" />
</KeyFrameSet>
</Transition>
...
</MotionScene>
Scene 1 - Part 6
@mikescamell
Frame 0 Frame 100Frame 70
Synopsis
Scene 1 - Part 6
@mikescamellScene 1 - Part 6
@mikescamellScene 1 - Part 7
Liquidy background
Liquidy background
@mikescamellScene 1 - Part 7
@mikescamellScene 1 - Part 7
shapeshifter.design
@mikescamell
topLeftAnimationForward ?.registerAnimationCallback(object :
Animatable2Compat.AnimationCallback() {
override fun onAnimationEnd(drawable: Drawable?) {
topLeftImageView.setImageDrawable(topLeftAnimationReverse)
topLeftAnimationReverse ?.start()
}
})
Scene 1 - Part 7
topLeftAnimationReverse ?.registerAnimationCallback(object :
Animatable2Compat.AnimationCallback() {
override fun onAnimationEnd(drawable: Drawable?) {
topLeftImageView.setImageDrawable(topLeftAnimationForward)
topLeftAnimationForward ?.start()
}
})
@mikescamellScene 1 - Part 7
@mikescamellScene 2 - Part 1
@mikescamellScene 2 - Part 1
@mikescamellScene 2 - Part 1
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_height="0dp"
app:layout_width="0dp" />
<Transform app:elevation="8dp" />
</Constraint>
</ConstraintSet>
</MotionScene>
Scene 2 - Part 1
@mikescamellScene 2 - Part 1
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_height="0dp"
app:layout_width="0dp" />
<Transform app:elevation="8dp" />
</Constraint>
</ConstraintSet>
</MotionScene>
Scene 2 - Part 1
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_height="0dp"
app:layout_width="0dp" />
<CustomAttribute
app:attributeName="radius"
app:customDimension="0dp" />
<Transform app:elevation="8dp" />
</Constraint>
</ConstraintSet>
</MotionScene>
Scene 2 - Part 1
@mikescamell
• Color
• Integer
• Float
• String
• Dimension
• Boolean
CustomAttribute
Scene 2 - Part 1
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout… />
<Transform app:elevation="4dp" />
</Constraint>
</ConstraintSet>
...
</MotionScene>
Scene 2 - Part 1
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout… />
<CustomAttribute
app:attributeName="radius"
app:customDimension="16dp" />
<Transform app:elevation="4dp" />
</Constraint>
</ConstraintSet>
...
</MotionScene>
Scene 2 - Part 1
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout ... />
<Transform app:elevation="8dp" />
</Constraint>
</ConstraintSet>
</MotionScene>
Scene 2 - Part 1
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/bookSynopsisCard">
<Layout ... />
<CustomAttribute
app:attributeName="radius"
app:customDimension="0dp" />
<Transform app:elevation="8dp" />
</Constraint>
</ConstraintSet>
</MotionScene>
Scene 2 - Part 1
@mikescamellScene 2 - Part 1
@mikescamellScene 2 - Part 2
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookCover">
<Layout
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bookSynopsisCard"
app:layout_width="150dp" />
<Transform
app:rotationX="-55"
app:translationY="-24dp" />
</Constraint>
</ConstraintSet>
...
</MotionScene>
Scene 2 - Part 2
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookCover">
<Layout
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/bookSynopsisCard"
app:layout_width="150dp" />
<Transform
app:elevation="4dp"
app:rotationX="-55"
app:translationY="-24dp" />
</Constraint>
</ConstraintSet>
...
</MotionScene>
Scene 2 - Part 2
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookCover">
<Layout ... />
<Transform ... />
</Constraint>
</ConstraintSet>
...
</MotionScene>
Scene 2 - Part 2
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/bookCover">
<Layout ... />
<Transform ... />
<CustomAttribute
app:attributeName="outlineSpotShadowColor"
app:customColorValue="@color/transparent" />
</Constraint>
</ConstraintSet>
...
</MotionScene>
Scene 2 - Part 2
@mikescamellScene 2 - Part 2
<MotionScene>
...
<ConstraintSet android:id=“@+id/end">
<Constraint android:id="@+id/bookCover">
<Layout ... />
<Transform
app:elevation="12dp"
app:rotationX="0"
app:translationY="24dp" />
<CustomAttribute
app:attributeName="outlineSpotShadowColor"
app:customColorValue=“@color/black" />
</Constraint>
</ConstraintSet>
...
</MotionScene>
@mikescamellScene 2 - Part 2
<MotionScene>
...
<ConstraintSet android:id=“@+id/end">
<Constraint android:id="@+id/bookCover">
<Layout ... />
<Transform
app:elevation="12dp"
app:rotationX="0"
app:translationY="24dp" />
<CustomAttribute
app:attributeName="outlineSpotShadowColor"
app:customColorValue=“@color/black" />
</Constraint>
</ConstraintSet>
...
</MotionScene>
@mikescamellScene 2 - Part 2
<MotionScene>
...
<ConstraintSet android:id=“@+id/end">
<Constraint android:id="@+id/bookCover">
<Layout ... />
<Transform
app:elevation="12dp"
app:rotationX="0"
app:translationY="24dp" />
<CustomAttribute
app:attributeName="outlineSpotShadowColor"
app:customColorValue=“@color/black" />
</Constraint>
</ConstraintSet>
...
</MotionScene>
@mikescamellScene 2 - Part 2
@mikescamellScene 2 - Part 3
@mikescamell
KEYATTRIBUTES
Scene 2 - Part 3
@mikescamell
<MotionScene>
<Transition ...>
<OnClick ... />
</Transition>
...
</MotionScene>
Scene 2 - Part 3
@mikescamell
<MotionScene>
<Transition ...>
<OnClick ... />
<KeyFrameSet>
<KeyAttribute
android:alpha="0"
app:framePosition="10"
app:target="@id/bookSynopsisTitle" />
<KeyAttribute
android:alpha="0"
app:framePosition="10"
app:target="@id/bookSynopsisText" />
</KeyFrameSet>
</Transition>
...
</MotionScene>
Scene 2 - Part 3
@mikescamell
<MotionScene>
<ConstraintSet android:id="@+id/start">
...
<Constraint android:id="@+id/bookSynopsisTitle">
<Transform app:elevation="4dp" />
<PropertySet app:alpha="1" />
</Constraint>
<Constraint android:id="@+id/bookSynopsisText">
<Transform app:elevation="4dp" />
<PropertySet app:alpha="1" />
</Constraint>
...
</ConstraintSet>
...
</MotionScene>
Scene 2 - Part 3
@mikescamell
<MotionScene>
...
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/bookSynopsisTitle">
<Transform app:elevation="8dp" />
<PropertySet app:alpha="0" />
</Constraint>
<Constraint android:id="@+id/bookSynopsisText">
<Transform app:elevation="8dp" />
<PropertySet app:alpha="0" />
</Constraint>
...
</ConstraintSet>
</MotionScene>
Scene 2 - Part 3
@mikescamellScene 2 - Part 3
@mikescamellScene 2 - Part 4
@mikescamellScene 2 - Part 4
<MotionLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/bookType"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="16dp"
android:elevation="8dp"
android:fontFamily="@font/lora_italic"
android:text="@string/novel"
android:textSize="12sp"
android:translationY="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/bookCover"
app:layout_constraintTop_toTopOf="@+id/bookCover" />
</MotionLayout>
@mikescamellScene 2 - Part 4
<MotionLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/bookType"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="16dp"
android:elevation="8dp"
android:fontFamily="@font/lora_italic"
android:text="@string/novel"
android:textSize="12sp"
android:translationY="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/bookCover"
app:layout_constraintTop_toTopOf="@+id/bookCover" />
</MotionLayout>
@mikescamell
<MotionScene>
<Transition ...>
<OnClick ... />
<KeyFrameSet>
<KeyAttribute
android:alpha="0"
app:framePosition="95"
app:target="@id/bookType" />
...
</KeyFrameSet>
</Transition>
...
</MotionScene>
Scene 2 - Part 4
@mikescamell
<MotionScene>
<Transition ...>
<OnClick ... />
<KeyFrameSet>
<KeyAttribute
android:alpha="0"
app:framePosition="95"
app:target="@id/bookType" />
...
</KeyFrameSet>
</Transition>
...
</MotionScene>
Scene 2 - Part 4
@mikescamellScene 2 - Part 4
@mikescamell
motionLayout.setTransitionListener(object : MotionLayout.TransitionListener {
override fun onTransitionTrigger(
motionLayout: MotionLayout, startId: Int, endId: Boolean, progress: Float
) {
}
override fun onTransitionStarted(
motionLayout: MotionLayout, startId: Int, endId: Int
) {
}
override fun onTransitionChange(
motionLayout: MotionLayout, startId: Int, endId: Int, progress: Float
) {
}
override fun onTransitionCompleted(motionLayout: MotionLayout, currentId: Int) {
}
})
Scene 2 - Part 4
@mikescamell
motionLayout.setTransitionListener(object : MotionLayout.TransitionListener {
...
override fun onTransitionChange(
motionLayout: MotionLayout, startId: Int, endId: Int, progress: Float
) {
}
...
})
Scene 2 - Part 4
@mikescamell
motionLayout.setTransitionListener(object : MotionLayout.TransitionListener {
...
override fun onTransitionChange(
motionLayout: MotionLayout, startId: Int, endId: Int, progress: Float
) {
val color =
ColorUtils.setAlphaComponent(Color.WHITE, calculateProgressAlpha(progress))
bottomRightAnimationForward ?.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
bottomRightAnimationReverse ?.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
}
...
})
Scene 2 - Part 4
@mikescamellScene 2 - Part 4
@mikescamellScene 2 - Part 5
@mikescamell
<ConstraintSet android:id="@+id/start">
...
<Constraint android:id="@+id/favourite">
<PropertySet app:alpha="0" />
</Constraint>
<Constraint android:id="@+id/bookmark">
<PropertySet app:alpha="0" />
</Constraint>
<Constraint android:id="@+id/readButton">
<PropertySet app:alpha="0" />
</Constraint>
</ConstraintSet>
Scene 2 - Part 5
@mikescamell
<MotionScene>
<Transition ...>
<OnClick ... />
<KeyFrameSet>
...
<KeyAttribute
android:alpha="0"
app:framePosition="80"
app:target="@id/favourite" />
<KeyAttribute
android:alpha="0"
app:framePosition="85"
app:target="@id/bookmark" />
<KeyAttribute
android:alpha="0"
app:framePosition="90"
app:target="@id/readButton" />
</KeyFrameSet>
</Transition>
</MotionScene>
Scene 2 - Part 5
@mikescamell
<MotionScene>
<Transition ...>
<OnClick ... />
<KeyFrameSet>
...
<KeyAttribute
android:alpha="0"
app:framePosition="80"
app:target="@id/favourite" />
<KeyAttribute
android:alpha="0"
app:framePosition="85"
app:target="@id/bookmark" />
<KeyAttribute
android:alpha="0"
app:framePosition="90"
app:target="@id/readButton" />
</KeyFrameSet>
</Transition>
</MotionScene>
Scene 2 - Part 5
@mikescamell
<MotionScene>
<Transition ...>
<OnClick ... />
<KeyFrameSet>
...
<KeyAttribute
android:alpha="0"
app:framePosition="80"
app:target="@id/favourite" />
<KeyAttribute
android:alpha="0"
app:framePosition="85"
app:target="@id/bookmark" />
<KeyAttribute
android:alpha="0"
app:framePosition="90"
app:target="@id/readButton" />
</KeyFrameSet>
</Transition>
</MotionScene>
Scene 2 - Part 5
@mikescamellScene 2 - Part 5
@mikescamellScene 2 - Part 5
@mikescamellScene 2 - Part 6
@mikescamell
<MotionLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:motionDebug="SHOW_PATH"
app:layoutDescription="@xml/scene2_part5">
Scene 2 - Part 6
@mikescamell
<MotionLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:motionDebug="SHOW_PROGRESS"
app:layoutDescription="@xml/scene2_part5">
Scene 2 - Part 6
@mikescamellScene 2 - Part 6
<KeyPosition />
@mikescamellScene 2 - Part 6
<KeyPosition
app:curveFit="linear" />
@mikescamellScene 2 - Part 6
<KeyPosition
app:curveFit="linear"
app:framePosition="0" />
@mikescamellScene 2 - Part 6
<KeyPosition
app:curveFit="linear"
app:framePosition="0"
app:keyPositionType="deltaRelative"
app:percentX="1" />
@mikescamellScene 2 - Part 6
Start Position
End Position
X
Y
1.0
1.0
Delta Relative
@mikescamellScene 2 - Part 6
X
Y
1.0
1.0
End Position
Start Position
Parent Relative
@mikescamellScene 2 - Part 6
X
Y
1.0
1.0
End Position
Start Position
Path Relative
@mikescamellScene 2 - Part 6
Start Position
End Position
X
Y
1.0
1.0
Delta Relative
@mikescamellScene 2 - Part 6
Start Position
End Position
X
Y
1.0
1.0
2.0
Delta Relative
@mikescamellScene 2 - Part 6
<KeyPosition
app:curveFit="linear"
app:framePosition="0"
app:keyPositionType="deltaRelative"
app:percentX="1" />
@mikescamellScene 2 - Part 6
<KeyPosition
app:curveFit="linear"
app:framePosition="0"
app:keyPositionType="deltaRelative"
app:percentX="1"
app:target="@+id/favourite" />
@mikescamellScene 2 - Part 6
<KeyPosition
app:curveFit="linear"
app:framePosition="0"
app:keyPositionType="deltaRelative"
app:percentX="1"
app:target="@+id/favourite"
app:transitionEasing="decelerate" />
@mikescamellScene 2 - Part 6
@mikescamell
<MotionScene>
<Transition ...>
<KeyFrameSet>
<KeyAttribute
android:alpha="0"
android:translationY="24dp"
app:framePosition="80"
app:target="@id/favourite" />
...
</KeyFrameSet>
</Transition>
...
</MotionScene>
Scene 2 - Part 6
@mikescamellScene 2 - Part 6
@mikescamellScene 2 - Part 7
@mikescamellScene 2 - Part 7
<MotionScene>
<ConstraintSet android:id="@+id/start">
...
<Constraint android:id="@+id/bookDetailScrollView">
<PropertySet app:alpha="0" />
<Layout
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent" />
</Constraint>
</ConstraintSet>
...
</MotionScene>
@mikescamellScene 2 - Part 7
<MotionScene>
...
<ConstraintSet android:id="@+id/end">
...
<Constraint android:id="@+id/bookDetailScrollView">
<PropertySet app:alpha="1" />
<Layout
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf=“@id/bookCover“ />
</Constraint>
</ConstraintSet>
</MotionScene>
@mikescamell
<MotionScene>
<Transition ...>
<KeyFrameSet>
<KeyAttribute
android:alpha="0"
app:framePosition="50"
app:target="@id/bookDetailScrollView" />
...
</KeyFrameSet>
</Transition>
...
</MotionScene>
Scene 2 - Part 7
@mikescamellScene 2 - Part 7
@mikescamell
<MotionScene>
<Transition
android:id="@+id/startToMiddle"
app:constraintSetEnd="@+id/middle"
app:constraintSetStart="@+id/start"
app:duration="1000">
<OnClick
app:clickAction="toggle"
app:target="@id/bookCover" />
<KeyFrameSet ... />
</Transition>
...
<ConstraintSet android:id="@+id/start" ... />
<ConstraintSet android:id="@+id/middle" ... />
<ConstraintSet android:id=“@+id/end" ... />
</MotionScene>
Combined Scene - Part 1,2,3
@mikescamell
<MotionScene>
...
<Transition
android:id="@+id/middleToEnd"
app:constraintSetEnd="@+id/end"
app:constraintSetStart="@+id/middle"
app:duration="1000">
<OnClick
app:clickAction="toggle"
app:target="@id/bookSynopsisCard" />
<KeyFrameSet ... />
</Transition>
<ConstraintSet android:id="@+id/start" ... />
<ConstraintSet android:id="@+id/middle" ... />
<ConstraintSet android:id=“@+id/end" ... />
</MotionScene>
Combined Scene - Part 1,2,3
@mikescamell
Considerations
• No GUI (in progress)
• Doesn’t work with RecyclerViews (likely in alpha04)
• It’s in alpha!
• Performance?
• Elevation shadow tweaking is only 28+
• Difficult to have multiple transitions using same target
@mikescamell
@mikescamell
Considerations
• No GUI (in progress)
• Doesn’t work with RecyclerViews (coming soon )
• It’s in alpha!
• Performance?
• Elevation shadow tweaking is only 28+
• Difficult to have multiple transitions using same target
@mikescamell
Summary
• Start out simple
• Use an empty project
• Read the blog posts & ask questions! #motionlayout
• Take advantage of Apply Changes
• HAVE FUN!
@mikescamell
But wait…
@mikescamell
@mikescamell
MWUHAHAHAHAHA
HAHAHAHAHAHAH
AHAHAHHAHAHAH
AHAHAHAHAHAHA
HAHAHAHAHAHAH
AHAHAHAHAHA!!!!!
L
O
L
O
L
O
L
O
L
O
L
O
L
O
L
@johnhoford
@mikescamell
THANK YOU!
Want to read the latest blog posts from Android Developers around
the world? Checkout:
androiddev.io
(please it’s costing me $5 a month)
Twitter: @mikescamell
Website: mikescamell.com
Podcast (on hiatus): androidsnacks.com
(Skip to the “funny” bits at the end)
Slides:
@mikescamell
Links
• Slides
- TODO
• Loco-MotionLayout Repo
- https://github.com/mikescamell/Loco-MotionLayout
• Nicolas Roard’s MotionLayout Series:
- https://medium.com/google-developers/introduction-to-motionlayout-part-i-29208674b10d
- https://medium.com/google-developers/introduction-to-motionlayout-part-ii-a31acc084f59
- https://medium.com/google-developers/introduction-to-motionlayout-part-iii-47cd64d51a5
- https://medium.com/google-developers/defining-motion-paths-in-motionlayout-6095b874d37
• Google Constraint/MotionLayout Example Repo
- https://github.com/googlesamples/android-ConstraintLayoutExamples
@mikescamell
Links
• MotionLayout Sunday 🎉 ™ (where the idea for this talk originated):
- https://twitter.com/MikeScamell/status/1071810532888457217
- https://twitter.com/MikeScamell/status/1074342193102495746
- https://twitter.com/MikeScamell/status/1076790689659322368
- https://twitter.com/MikeScamell/status/1079508256857436160
- https://twitter.com/MikeScamell/status/1082037771362029574
• ShapeShifter (Creating AnimatedVectorDrawables)
- https://shapeshifter.design/
• PorterDuff.Mode
- https://developer.android.com/reference/android/graphics/PorterDuff.Mode
@mikescamell
• TODO add more videos
• Check for todo slides

More Related Content

PPT
Responsive Images FCIP July 2013
PDF
Responsive images are here. Now what?
PPTX
06 UI Layout
PPTX
06. Android Basic Widget and Container
PPTX
Shared Element Transitions
PDF
Breaking Limits on Mobile HTML5 - TopConf Tallinn
PPTX
Fernando F. Gallego - Efficient Android Resources 101
Responsive Images FCIP July 2013
Responsive images are here. Now what?
06 UI Layout
06. Android Basic Widget and Container
Shared Element Transitions
Breaking Limits on Mobile HTML5 - TopConf Tallinn
Fernando F. Gallego - Efficient Android Resources 101

Similar to Do the Loco-MotionLayout: Building animations with MotionLayout (20)

PDF
Chapter 5 - Layouts
PDF
Android Material Design APIs/Tips
PDF
Fragments: Why, How, What For?
PDF
Data binding 入門淺談
DOCX
1. shared pref
PDF
Beauty Treatment for your Android Application
PDF
Android 2D Drawing and Animation Framework
PDF
How to use data binding in android
PDF
Android JetPack: easy navigation with the new Navigation Controller
PDF
Mobile First Responsive Design
KEY
Design Patterns for Tablets and Smartphones
PDF
Pinkoi Mobile Web
PDF
Support Design Library
PPT
Eye candy for your iPhone
PPTX
Android Layout
PDF
Building responsive web mobile mapping applications
PDF
Building iPad apps with Flex - 360Flex
PDF
Responsive websites. Toolbox
PPTX
Make your app dance with MotionLayout
PDF
Web mapping with vector data. Is it the future ? 2012
Chapter 5 - Layouts
Android Material Design APIs/Tips
Fragments: Why, How, What For?
Data binding 入門淺談
1. shared pref
Beauty Treatment for your Android Application
Android 2D Drawing and Animation Framework
How to use data binding in android
Android JetPack: easy navigation with the new Navigation Controller
Mobile First Responsive Design
Design Patterns for Tablets and Smartphones
Pinkoi Mobile Web
Support Design Library
Eye candy for your iPhone
Android Layout
Building responsive web mobile mapping applications
Building iPad apps with Flex - 360Flex
Responsive websites. Toolbox
Make your app dance with MotionLayout
Web mapping with vector data. Is it the future ? 2012
Ad

Recently uploaded (20)

PDF
Design an Analysis of Algorithms I-SECS-1021-03
PPTX
Why Generative AI is the Future of Content, Code & Creativity?
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PPTX
CHAPTER 2 - PM Management and IT Context
PDF
Nekopoi APK 2025 free lastest update
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PDF
System and Network Administraation Chapter 3
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PDF
Digital Systems & Binary Numbers (comprehensive )
PDF
Understanding Forklifts - TECH EHS Solution
PDF
PTS Company Brochure 2025 (1).pdf.......
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PPTX
Log360_SIEM_Solutions Overview PPT_Feb 2020.pptx
PPTX
Computer Software and OS of computer science of grade 11.pptx
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PPTX
assetexplorer- product-overview - presentation
PDF
medical staffing services at VALiNTRY
Design an Analysis of Algorithms I-SECS-1021-03
Why Generative AI is the Future of Content, Code & Creativity?
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
CHAPTER 2 - PM Management and IT Context
Nekopoi APK 2025 free lastest update
Operating system designcfffgfgggggggvggggggggg
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
wealthsignaloriginal-com-DS-text-... (1).pdf
System and Network Administraation Chapter 3
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
Digital Systems & Binary Numbers (comprehensive )
Understanding Forklifts - TECH EHS Solution
PTS Company Brochure 2025 (1).pdf.......
Design an Analysis of Algorithms II-SECS-1021-03
Log360_SIEM_Solutions Overview PPT_Feb 2020.pptx
Computer Software and OS of computer science of grade 11.pptx
Which alternative to Crystal Reports is best for small or large businesses.pdf
Odoo Companies in India – Driving Business Transformation.pdf
assetexplorer- product-overview - presentation
medical staffing services at VALiNTRY
Ad

Do the Loco-MotionLayout: Building animations with MotionLayout