Do the Loco-MotionLayout - droidcon Boston 2019

Do the Loco-MotionLayout - droidcon Boston 2019

A presentation on implementing a crazy dribbble design using MotionLayout.

2a389d50c33966a79a8cf6fe29c6080e?s=128

Michael Scamell

April 08, 2019
Tweet

Transcript

  1. @mikescamell Do the Loco-MotionLayout droidcon Boston 2019 @mikescamell HERE!!!

  2. @mikescamell Before we begin…

  3. @mikescamell

  4. @mikescamell MWUHAHAHAHAHA HAHAHAHAHAHAH AHAHAHHAHAHAH AHAHAHAHAHAHA HAHAHAHAHAHAH AHAHAHAHAHA!!!!! L O L

    O L O L O L O L O L O L @johnhoford
  5. @mikescamell by Nikita Duhovny

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

    layout transitions with TransitionManager, and CoordinatorLayout” MotionLayout
  7. @mikescamell Scene 1 - Part 1

  8. @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>
  9. @mikescamell Scene 1 - Part 1

  10. @mikescamell dependencies { implementation ‘com.android.support.constraint:constraint-layout:2.0.0-alpha4' } Scene 1 - Part

    2
  11. @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>
  12. @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>
  13. @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
  14. @mikescamell Scene 1 - Part 2

  15. @mikescamell Scene 1 - Part 2 <MotionScene> </MotionScene>

  16. @mikescamell Scene 1 - Part 2 <MotionScene> <Transition android:id="@+id/startToEnd" app:constraintSetStart="@+id/start"

    app:constraintSetEnd="@+id/end"> </Transition> </MotionScene>
  17. @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
  18. @mikescamell Scene 1 - Part 2

  19. @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>
  20. @mikescamell <MotionScene> ... </MotionScene> Scene 1 - Part 2

  21. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/start"> </ConstraintSet> </MotionScene> Scene 1 -

    Part 2
  22. @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 android:rotationX="0" android:translationY=“0dp" /> </Constraint> </ConstraintSet> … </MotionScene>
  23. @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 android:rotationX="0" android:translationY=“0dp" /> </Constraint> </ConstraintSet> </MotionScene>
  24. @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 android:rotationX="0" android:translationY=“0dp" /> </Constraint> </ConstraintSet> </MotionScene>
  25. @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 android:rotationX="0" android:translationY=“0dp" /> </Constraint> </ConstraintSet> </MotionScene>
  26. @mikescamell Scene 1 - Part 2 <MotionScene> ... <ConstraintSet android:id="@+id/start">

    <Constraint android:id="@+id/bookCover"> <Transform android:rotationX="0" android:translationY=“0dp" /> </Constraint> </ConstraintSet> </MotionScene>
  27. @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 android:rotationX=“-55"> </Constraint> </ConstraintSet> </MotionScene> Scene 1 - Part 2
  28. @mikescamell Scene 1 - Part 2

  29. @mikescamell Scene 1 - Part 3

  30. @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>
  31. @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
  32. @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 android:rotationX="-55" /> </Constraint> ... </ConstraintSet> ... </MotionScene> Scene 1 - Part 3
  33. @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 android:rotationX=“-55" /> </Constraint> ... </ConstraintSet> ... </MotionScene> Scene 1 - Part 3
  34. @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 android:rotationX=“-55" /> </Constraint> ... </ConstraintSet> ... </MotionScene> Scene 1 - Part 3
  35. @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 android:rotationX=“0" /> </Constraint> ... </ConstraintSet> </MotionScene> Scene 1 - Part 3
  36. @mikescamell Scene 1 - Part 3 <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 android:rotationX=“0" /> </Constraint> ... </ConstraintSet> </MotionScene>
  37. @mikescamell Scene 1 - Part 3 <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 android:rotationX=“0" /> </Constraint> ... </ConstraintSet> </MotionScene>
  38. @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 android:rotationX="-55" android:translationY=“-24dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 1 - Part 3
  39. @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 android:rotationX="-55" android:translationY=“-24dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 1 - Part 3
  40. @mikescamell Scene 1 - Part 3

  41. @mikescamell Scene 1 - Part 3

  42. @mikescamell Scene 1 - Part 4

  43. @mikescamell Scene 1 - Part 4

  44. @mikescamell Scene 1 - Part 5

  45. @mikescamell Scene 1 - Part 6

  46. @mikescamell Scene 1 - Part 6 • KeyAttribute • KeyPosition

    • KeyCycle • KeyTimeCycle • KeyTrigger KeyFrames
  47. @mikescamell <MotionScene> <Transition ...> <KeyFrameSet> <KeyAttribute android:alpha="0" app:framePosition="70" app:motionTarget="@id/bookSynopsisTitle" />

    <KeyAttribute android:alpha="0" app:framePosition="70" app:motionTarget="@id/bookSynopsisText" /> </KeyFrameSet> </Transition> ... </MotionScene> Scene 1 - Part 6
  48. @mikescamell Scene 1 - Part 6 0% 100% 70% Synopsis

  49. @mikescamell Scene 1 - Part 6

  50. @mikescamell Scene 1 - Part 7 Liquidy background Liquidy background

  51. @mikescamell Scene 1 - Part 7 End Start

  52. @mikescamell Scene 1 - Part 7 shapeshifter.design

  53. @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() } })
  54. @mikescamell Scene 1 - Part 7

  55. @mikescamell Scene 2 - Part 1

  56. @mikescamell Scene 2 - Part 1

  57. @mikescamell Scene 2 - Part 1

  58. @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.3" app:layout_height="300dp" app:layout_width="300dp" /> <Transform android:elevation="4dp" /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 1
  59. @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 android:elevation=“8dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 2 - Part 1
  60. @mikescamell <MotionScene> <Transition android:id="@+id/startToEnd" app:constraintSetEnd="@+id/end" app:constraintSetStart="@+id/start" >a </Transition> ... </MotionScene>

    Scene 2 - Part 1
  61. @mikescamell Scene 2 - Part 1 <MotionScene> <Transition android:id="@+id/startToEnd" app:constraintSetEnd="@+id/end"

    app:constraintSetStart=“@+id/start” app:duration=“1000" >a <OnClick app:clickAction="toggle" app:targetId=“@id/bookSynopsisCard" /> </Transition> ... </MotionScene>
  62. @mikescamell Scene 2 - Part 1 <OnClick app:clickAction=“jumpToStart|transitionToEnd” />

  63. @mikescamell Scene 2 - Part 1 <MotionScene> <Transition android:id="@+id/startToEnd" app:constraintSetEnd="@+id/end"

    app:constraintSetStart=“@+id/start” app:duration=“1000" > <OnClick app:clickAction="toggle" app:targetId=“@id/bookSynopsisCard" /> </Transition> ... </MotionScene>
  64. @mikescamell Scene 2 - Part 1 <MotionScene> <Transition android:id="@+id/startToEnd" app:constraintSetEnd="@+id/end"

    app:constraintSetStart=“@+id/start” app:duration=“1000" > <OnClick app:clickAction="toggle" app:targetId=“@id/bookSynopsisCard" /> </Transition> ... </MotionScene>
  65. @mikescamell Scene 2 - Part 1 <MotionScene> <Transition android:id="@+id/startToEnd" app:constraintSetEnd="@+id/end"

    app:constraintSetStart=“@+id/start” app:duration=“1000" > <OnClick app:clickAction="toggle" app:targetId=“@id/bookSynopsisCard" /> </Transition> ... </MotionScene>
  66. @mikescamell Scene 2 - Part 1

  67. @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 android:elevation=“8dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 2 - Part 1
  68. @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 android:elevation=“8dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 2 - Part 1
  69. @mikescamell • Color • Integer • Float • String •

    Dimension • Boolean • Pixel (new in alpha4) CustomAttribute Scene 2 - Part 1
  70. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/bookSynopsisCard"> <Layout… /> <Transform

    android:elevation=“4dp" /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 1
  71. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/bookSynopsisCard"> <Layout… /> <CustomAttribute

    app:attributeName="radius" app:customDimension="16dp" /> <Transform android:elevation=“4dp" /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 1
  72. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/bookSynopsisCard"> <Layout ... />

    <Transform android:elevation=“8dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 2 - Part 1
  73. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/bookSynopsisCard"> <Layout ... />

    <CustomAttribute app:attributeName="radius" app:customDimension="0dp" /> <Transform android:elevation=“8dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 2 - Part 1
  74. @mikescamell Scene 2 - Part 1

  75. @mikescamell Scene 2 - Part 2

  76. @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 android:rotationX="-55" android:translationY=“-24dp" /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 2
  77. @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 android:elevation="4dp" android:rotationX="-55" android:translationY=“-24dp" /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 2
  78. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/bookCover"> <Layout ... />

    <Transform ... /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 2
  79. @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
  80. @mikescamell Scene 2 - Part 2 <MotionScene> ... <ConstraintSet android:id=“@+id/end">

    <Constraint android:id="@+id/bookCover"> <Layout ... /> <Transform android:elevation="12dp" android:rotationX="0" android:translationY=“24dp" /> <CustomAttribute app:attributeName="outlineSpotShadowColor" app:customColorValue=“@color/black" /> </Constraint> </ConstraintSet> ... </MotionScene>
  81. @mikescamell Scene 2 - Part 2 <MotionScene> ... <ConstraintSet android:id=“@+id/end">

    <Constraint android:id="@+id/bookCover"> <Layout ... /> <Transform android:elevation="12dp" android:rotationX="0" android:translationY=“24dp" /> <CustomAttribute app:attributeName="outlineSpotShadowColor" app:customColorValue=“@color/black" /> </Constraint> </ConstraintSet> ... </MotionScene>
  82. @mikescamell Scene 2 - Part 2 <MotionScene> ... <ConstraintSet android:id=“@+id/end">

    <Constraint android:id="@+id/bookCover"> <Layout ... /> <Transform android:elevation="12dp" android:rotationX="0" android:translationY=“24dp" /> <CustomAttribute app:attributeName="outlineSpotShadowColor" app:customColorValue=“@color/black" /> </Constraint> </ConstraintSet> ... </MotionScene>
  83. @mikescamell Scene 2 - Part 2

  84. @mikescamell Scene 2 - Part 3

  85. @mikescamell KEYATTRIBUTES Scene 2 - Part 3

  86. @mikescamell <MotionScene> <Transition ...> <OnClick ... /> </Transition> ... </MotionScene>

    Scene 2 - Part 3
  87. @mikescamell <MotionScene> <Transition ...> <OnClick ... /> <KeyFrameSet> <KeyAttribute android:alpha="0"

    app:framePosition="10" app:motionTarget="@id/bookSynopsisTitle" /> <KeyAttribute android:alpha="0" app:framePosition="10" app:motionTarget="@id/bookSynopsisText" /> </KeyFrameSet> </Transition> ... </MotionScene> Scene 2 - Part 3
  88. @mikescamell <MotionScene> <ConstraintSet android:id="@+id/start"> ... <Constraint android:id="@+id/bookSynopsisTitle"> <Transform android:elevation=“4dp" />

    <PropertySet app:alpha="1" /> </Constraint> <Constraint android:id="@+id/bookSynopsisText"> <Transform android:elevation="4dp" /> <PropertySet app:alpha="1" /> </Constraint> ... </ConstraintSet> ... </MotionScene> Scene 2 - Part 3
  89. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/bookSynopsisTitle"> <Transform android:elevation="8dp" />

    <PropertySet app:alpha="0" /> </Constraint> <Constraint android:id="@+id/bookSynopsisText"> <Transform android:elevation=“8dp" /> <PropertySet app:alpha="0" /> </Constraint> ... </ConstraintSet> </MotionScene> Scene 2 - Part 3
  90. @mikescamell Scene 2 - Part 3

  91. @mikescamell Scene 2 - Part 4

  92. @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>
  93. @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>
  94. @mikescamell <MotionScene> <Transition ...> <OnClick ... /> <KeyFrameSet> <KeyAttribute android:alpha="0"

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

    app:framePosition="95" app:motionTarget="@id/bookType" /> ... </KeyFrameSet> </Transition> ... </MotionScene> Scene 2 - Part 4
  96. @mikescamell Scene 2 - Part 4

  97. @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 ) {g }x override fun onTransitionCompleted(motionLayout: MotionLayout, currentId: Int) { } }) Scene 2 - Part 4
  98. @mikescamell motionLayout.setTransitionListener(object : MotionLayout.TransitionListener { ... override fun onTransitionChange( motionLayout:

    MotionLayout, startId: Int, endId: Int, progress: Float ) {g }x ... }) Scene 2 - Part 4
  99. @mikescamell motionLayout.setTransitionListener(object : MotionLayout.TransitionListener { ... override fun onTransitionChange( motionLayout:

    MotionLayout, startId: Int, endId: Int, progress: Float ) {g val color = ColorUtils.setAlphaComponent(Color.WHITE, calculateProgressAlpha(progress)) bottomRightAnimationForward ?.setColorFilter(color, PorterDuff.Mode.SRC_ATOP) bottomRightAnimationReverse ?.setColorFilter(color, PorterDuff.Mode.SRC_ATOP) }x ... }) Scene 2 - Part 4
  100. @mikescamell Scene 2 - Part 4

  101. @mikescamell Scene 2 - Part 5

  102. @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
  103. @mikescamell <MotionScene> <Transition ...> <OnClick ... /> <KeyFrameSet> ... <KeyAttribute

    android:alpha="0" app:framePosition="80" app:motionTarget="@id/favourite" /> <KeyAttribute android:alpha="0" app:framePosition="85" app:motionTarget="@id/bookmark" /> <KeyAttribute android:alpha="0" app:framePosition="90" app:motionTarget="@id/readButton" /> </KeyFrameSet> </Transition> </MotionScene> Scene 2 - Part 5
  104. @mikescamell <MotionScene> <Transition ...> <OnClick ... /> <KeyFrameSet> ... <KeyAttribute

    android:alpha="0" app:framePosition="80" app:motionTarget="@id/favourite" /> <KeyAttribute android:alpha="0" app:framePosition="85" app:motionTarget="@id/bookmark" /> <KeyAttribute android:alpha="0" app:framePosition="90" app:motionTarget="@id/readButton" /> </KeyFrameSet> </Transition> </MotionScene> Scene 2 - Part 5
  105. @mikescamell <MotionScene> <Transition ...> <OnClick ... /> <KeyFrameSet> ... <KeyAttribute

    android:alpha="0" app:framePosition="80" app:motionTarget="@id/favourite" /> <KeyAttribute android:alpha="0" app:framePosition="85" app:motionTarget="@id/bookmark" /> <KeyAttribute android:alpha="0" app:framePosition="90" app:motionTarget="@id/readButton" /> </KeyFrameSet> </Transition> </MotionScene> Scene 2 - Part 5
  106. @mikescamell Scene 2 - Part 5

  107. @mikescamell Scene 2 - Part 5

  108. @mikescamell Scene 2 - Part 6

  109. @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
  110. @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
  111. @mikescamell Scene 2 - Part 6 <KeyPosition />

  112. @mikescamell Scene 2 - Part 6 <KeyPosition app:curveFit="linear" />

  113. @mikescamell Scene 2 - Part 6 <KeyPosition app:curveFit="linear" app:framePosition="0" />

  114. @mikescamell Scene 2 - Part 6 <KeyPosition app:curveFit="linear" app:framePosition="0" app:keyPositionType="deltaRelative"

    app:percentX="1" />
  115. @mikescamell Scene 2 - Part 6 Start Position End Position

    X Y 1.0 1.0 Delta Relative
  116. @mikescamell Scene 2 - Part 6 X Y 1.0 1.0

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

    End Position Start Position Path Relative
  118. @mikescamell Scene 2 - Part 6 Start Position End Position

    X Y 1.0 1.0 Delta Relative
  119. @mikescamell Scene 2 - Part 6 Start Position End Position

    X Y 1.0 1.0 2.0 Delta Relative
  120. @mikescamell Scene 2 - Part 6 <KeyPosition app:curveFit="linear" app:framePosition="0" app:keyPositionType="deltaRelative"

    app:percentX="1" />
  121. @mikescamell Scene 2 - Part 6 <KeyPosition app:curveFit="linear" app:framePosition="0" app:keyPositionType="deltaRelative"

    app:percentX="1" app:target="@+id/favourite" />
  122. @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" />
  123. @mikescamell Scene 2 - Part 6

  124. @mikescamell <MotionScene> <Transition ...> <KeyFrameSet> <KeyAttribute android:alpha="0" android:translationY="24dp" app:framePosition="80" app:motionTarget="@id/favourite"

    /> ... </KeyFrameSet> </Transition> ... </MotionScene> Scene 2 - Part 6
  125. @mikescamell Scene 2 - Part 6

  126. @mikescamell Scene 2 - Part 7

  127. @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>
  128. @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>
  129. @mikescamell <MotionScene> <Transition ...> <KeyFrameSet> <KeyAttribute android:alpha="0" app:framePosition="50" app:motionTarget="@id/bookDetailScrollView" />

    ... </KeyFrameSet> </Transition> ... </MotionScene> Scene 2 - Part 7
  130. @mikescamell Scene 2 - Part 7

  131. @mikescamell <MotionScene> <Transitionk android:id="@+id/startToMiddle"k app:constraintSetEnd="@+id/middle"k app:constraintSetStart="@+id/start"k app:duration="1000">k <OnClickk app:clickAction="toggle"k app:targetId="@id/bookCover"

    />k <KeyFrameSet ...k />k </Transition>k ...l <ConstraintSet android:id="@+id/start" ... /> <ConstraintSet android:id="@+id/middle" ... /> <ConstraintSet android:id=“@+id/end" ... /> </MotionScene> Combined Scene - Part 1,2,3
  132. @mikescamell <MotionScene> ... <Transition android:id="@+id/middleToEnd" app:constraintSetEnd="@+id/end" app:constraintSetStart="@+id/middle" app:duration="1000"> <OnClick app:clickAction="toggle"

    app:targetId="@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
  133. @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
  134. @mikescamell

  135. @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
  136. @mikescamell Summary • Start out simple • Use an empty

    project • Read the blog posts & ask questions! #motionlayout • Take advantage of Apply Changes • HAVE FUN!
  137. @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
  138. @mikescamell Links • Loco-MotionLayout Repo - https:/ /github.com/mikescamell/Loco-MotionLayout (checkout the

    alpha4_fixed branch) • 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
  139. @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