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

Do the Loco-MotionLayout: Building animations w...

Do the Loco-MotionLayout: Building animations with MotionLayout

A talk on building a crazy animation from dribbble using MotionLayout, presented at droidcon Italy.

Avatar for Michael Scamell

Michael Scamell

April 05, 2019
Tweet

More Decks by Michael Scamell

Other Decks in Technology

Transcript

  1. – Nicolas Roard “A mix between the property animation framework,

    layout transitions with TransitionManager, and CoordinatorLayout” MotionLayout
  2. @mikescamell Scene 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>
  3. @mikescamell Scene 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>
  4. @mikescamell Scene 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>
  5. @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
  6. @mikescamell Scene 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>
  7. @mikescamell Scene 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>
  8. @mikescamell Scene 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>
  9. @mikescamell Scene 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>
  10. @mikescamell Scene 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>
  11. @mikescamell Scene 1 - Part 2 <MotionScene> ... <ConstraintSet android:id="@+id/start">

    <Constraint android:id="@+id/bookCover"> <Transform app:rotationX="0" app:translationY="0dp" /> </Constraint> </ConstraintSet> </MotionScene>
  12. @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
  13. @mikescamell Scene 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>
  14. @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
  15. @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
  16. @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
  17. @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
  18. @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
  19. @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
  20. @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
  21. @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
  22. @mikescamell Scene 1 - Part 6 • KeyAttribute • KeyPosition

    • KeyCycle • KeyTimeCycle • KeyTrigger KeyFrames
  23. @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
  24. @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() } })
  25. @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
  26. @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
  27. @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
  28. @mikescamell • Color • Integer • Float • String •

    Dimension • Boolean CustomAttribute Scene 2 - Part 1
  29. @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
  30. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/bookSynopsisCard"> <Layout ... />

    <Transform app:elevation="8dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 2 - Part 1
  31. @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
  32. @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
  33. @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
  34. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/bookCover"> <Layout ... />

    <Transform ... /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 2
  35. @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
  36. @mikescamell Scene 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>
  37. @mikescamell Scene 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>
  38. @mikescamell Scene 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>
  39. @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
  40. @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
  41. @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
  42. @mikescamell Scene 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>
  43. @mikescamell Scene 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>
  44. @mikescamell <MotionScene> <Transition ...> <OnClick ... /> <KeyFrameSet> <KeyAttribute android:alpha="0"

    app:framePosition="95" app:target="@id/bookType" /> ... </KeyFrameSet> </Transition> ... </MotionScene> Scene 2 - Part 4
  45. @mikescamell <MotionScene> <Transition ...> <OnClick ... /> <KeyFrameSet> <KeyAttribute android:alpha="0"

    app:framePosition="95" app:target="@id/bookType" /> ... </KeyFrameSet> </Transition> ... </MotionScene> Scene 2 - Part 4
  46. @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
  47. @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
  48. @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
  49. @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
  50. @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
  51. @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
  52. @mikescamell Scene 2 - Part 6 X Y 1.0 1.0

    End Position Start Position Parent Relative
  53. @mikescamell Scene 2 - Part 6 X Y 1.0 1.0

    End Position Start Position Path Relative
  54. @mikescamell Scene 2 - Part 6 <KeyPosition app:curveFit="linear" app:framePosition="0" app:keyPositionType="deltaRelative"

    app:percentX="1" app:target="@+id/favourite" app:transitionEasing="decelerate" />
  55. @mikescamell Scene 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>
  56. @mikescamell Scene 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>
  57. @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
  58. @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
  59. @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
  60. @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
  61. @mikescamell Summary • Start out simple • Use an empty

    project • Read the blog posts & ask questions! #motionlayout • Take advantage of Apply Changes • HAVE FUN!
  62. @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: http:/ /bit.ly/loco-motionlayout
  63. @mikescamell Links • Slides - http:/ /bit.ly/loco-motionlayout • 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
  64. @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