Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Do the Loco-MotionLayout: Building animations with MotionLayout

1,179 views

Published on

A talk showing how to build a "complex" animation using the new MotionLayout library.

Published in: Software
  • Be the first to comment

Do the Loco-MotionLayout: Building animations with MotionLayout

  1. 1. @mikescamell Do the Loco-MotionLayout @mikescamell HERE!!!
  2. 2. @mikescamell by Nikita Duhovny 
  3. 3. – Nicolas Roard “A mix between the property animation framework, layout transitions with TransitionManager, and CoordinatorLayout” MotionLayout
  4. 4. @mikescamellScene 1 - Part 1
  5. 5. @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>
  6. 6. @mikescamellScene 1 - Part 1
  7. 7. @mikescamell (Yes yes yes I know!) dependencies {   implementation 'com.android.support.constraint:constraint-layout:2.0.0-alpha3' }
  8. 8. @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>
  9. 9. @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>
  10. 10. @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
  11. 11. @mikescamell
  12. 12. @mikescamellScene 1 - Part 2 <MotionScene> </MotionScene>
  13. 13. @mikescamellScene 1 - Part 2 <MotionScene> <Transition android:id="@+id/startToEnd" app:constraintSetStart="@+id/start" app:constraintSetEnd="@+id/end"> </Transition> </MotionScene>
  14. 14. @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
  15. 15. @mikescamellScene 1 - Part 2
  16. 16. @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>
  17. 17. @mikescamell <MotionScene> ... </MotionScene> Scene 1 - Part 2
  18. 18. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/start"> </ConstraintSet> </MotionScene> Scene 1 - Part 2
  19. 19. @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>
  20. 20. @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>
  21. 21. @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>
  22. 22. @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>
  23. 23. @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>
  24. 24. @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
  25. 25. @mikescamellScene 1 - Part 2
  26. 26. @mikescamellScene 1 - Part 3
  27. 27. @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>
  28. 28. @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
  29. 29. @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
  30. 30. @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
  31. 31. @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
  32. 32. @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
  33. 33. @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
  34. 34. @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
  35. 35. @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
  36. 36. @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
  37. 37. @mikescamellScene 1 - Part 3
  38. 38. @mikescamellScene 1 - Part 3
  39. 39. @mikescamellScene 1 - Part 4
  40. 40. @mikescamellScene 1 - Part 4
  41. 41. @mikescamellScene 1 - Part 5
  42. 42. @mikescamellScene 1 - Part 6
  43. 43. @mikescamellScene 1 - Part 6 • KeyAttribute • KeyPosition • KeyCycle • KeyTimeCycle • KeyTrigger KeyFrames
  44. 44. @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
  45. 45. @mikescamell Frame 0 Frame 100Frame 70 Synopsis Scene 1 - Part 6
  46. 46. @mikescamellScene 1 - Part 6
  47. 47. @mikescamellScene 1 - Part 7 Liquidy background Liquidy background
  48. 48. @mikescamellScene 1 - Part 7
  49. 49. @mikescamellScene 1 - Part 7 shapeshifter.design
  50. 50. @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() } })
  51. 51. @mikescamellScene 1 - Part 7
  52. 52. @mikescamellScene 2 - Part 1
  53. 53. @mikescamellScene 2 - Part 1
  54. 54. @mikescamellScene 2 - Part 1
  55. 55. @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
  56. 56. @mikescamellScene 2 - Part 1
  57. 57. @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
  58. 58. @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
  59. 59. @mikescamell • Color • Integer • Float • String • Dimension • Boolean CustomAttribute Scene 2 - Part 1
  60. 60. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/bookSynopsisCard"> <Layout… /> <Transform app:elevation="4dp" /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 1
  61. 61. @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
  62. 62. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/bookSynopsisCard"> <Layout ... /> <Transform app:elevation="8dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 2 - Part 1
  63. 63. @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
  64. 64. @mikescamellScene 2 - Part 1
  65. 65. @mikescamellScene 2 - Part 2
  66. 66. @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
  67. 67. @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
  68. 68. @mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/bookCover"> <Layout ... /> <Transform ... /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 2
  69. 69. @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
  70. 70. @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>
  71. 71. @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>
  72. 72. @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>
  73. 73. @mikescamellScene 2 - Part 2
  74. 74. @mikescamellScene 2 - Part 3
  75. 75. @mikescamell KEYATTRIBUTES Scene 2 - Part 3
  76. 76. @mikescamell <MotionScene> <Transition ...> <OnClick ... /> </Transition> ... </MotionScene> Scene 2 - Part 3
  77. 77. @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
  78. 78. @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
  79. 79. @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
  80. 80. @mikescamellScene 2 - Part 3
  81. 81. @mikescamellScene 2 - Part 4
  82. 82. @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>
  83. 83. @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>
  84. 84. @mikescamell <MotionScene> <Transition ...> <OnClick ... /> <KeyFrameSet> <KeyAttribute android:alpha="0" app:framePosition="95" app:target="@id/bookType" /> ... </KeyFrameSet> </Transition> ... </MotionScene> Scene 2 - Part 4
  85. 85. @mikescamell <MotionScene> <Transition ...> <OnClick ... /> <KeyFrameSet> <KeyAttribute android:alpha="0" app:framePosition="95" app:target="@id/bookType" /> ... </KeyFrameSet> </Transition> ... </MotionScene> Scene 2 - Part 4
  86. 86. @mikescamellScene 2 - Part 4
  87. 87. @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
  88. 88. @mikescamell motionLayout.setTransitionListener(object : MotionLayout.TransitionListener { ... override fun onTransitionChange( motionLayout: MotionLayout, startId: Int, endId: Int, progress: Float ) { } ... }) Scene 2 - Part 4
  89. 89. @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
  90. 90. @mikescamellScene 2 - Part 4
  91. 91. @mikescamellScene 2 - Part 5
  92. 92. @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
  93. 93. @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
  94. 94. @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
  95. 95. @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
  96. 96. @mikescamellScene 2 - Part 5
  97. 97. @mikescamellScene 2 - Part 5
  98. 98. @mikescamellScene 2 - Part 6
  99. 99. @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
  100. 100. @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
  101. 101. @mikescamellScene 2 - Part 6 <KeyPosition />
  102. 102. @mikescamellScene 2 - Part 6 <KeyPosition app:curveFit="linear" />
  103. 103. @mikescamellScene 2 - Part 6 <KeyPosition app:curveFit="linear" app:framePosition="0" />
  104. 104. @mikescamellScene 2 - Part 6 <KeyPosition app:curveFit="linear" app:framePosition="0" app:keyPositionType="deltaRelative" app:percentX="1" />
  105. 105. @mikescamellScene 2 - Part 6 Start Position End Position X Y 1.0 1.0 Delta Relative
  106. 106. @mikescamellScene 2 - Part 6 X Y 1.0 1.0 End Position Start Position Parent Relative
  107. 107. @mikescamellScene 2 - Part 6 X Y 1.0 1.0 End Position Start Position Path Relative
  108. 108. @mikescamellScene 2 - Part 6 Start Position End Position X Y 1.0 1.0 Delta Relative
  109. 109. @mikescamellScene 2 - Part 6 Start Position End Position X Y 1.0 1.0 2.0 Delta Relative
  110. 110. @mikescamellScene 2 - Part 6 <KeyPosition app:curveFit="linear" app:framePosition="0" app:keyPositionType="deltaRelative" app:percentX="1" />
  111. 111. @mikescamellScene 2 - Part 6 <KeyPosition app:curveFit="linear" app:framePosition="0" app:keyPositionType="deltaRelative" app:percentX="1" app:target="@+id/favourite" />
  112. 112. @mikescamellScene 2 - Part 6 <KeyPosition app:curveFit="linear" app:framePosition="0" app:keyPositionType="deltaRelative" app:percentX="1" app:target="@+id/favourite" app:transitionEasing="decelerate" />
  113. 113. @mikescamellScene 2 - Part 6
  114. 114. @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
  115. 115. @mikescamellScene 2 - Part 6
  116. 116. @mikescamellScene 2 - Part 7
  117. 117. @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>
  118. 118. @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>
  119. 119. @mikescamell <MotionScene> <Transition ...> <KeyFrameSet> <KeyAttribute android:alpha="0" app:framePosition="50" app:target="@id/bookDetailScrollView" /> ... </KeyFrameSet> </Transition> ... </MotionScene> Scene 2 - Part 7
  120. 120. @mikescamellScene 2 - Part 7
  121. 121. @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
  122. 122. @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
  123. 123. @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
  124. 124. @mikescamell
  125. 125. @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
  126. 126. @mikescamell Summary • Start out simple • Use an empty project • Read the blog posts & ask questions! #motionlayout • Take advantage of Apply Changes • HAVE FUN!
  127. 127. @mikescamell But wait…
  128. 128. @mikescamell
  129. 129. @mikescamell MWUHAHAHAHAHA HAHAHAHAHAHAH AHAHAHHAHAHAH AHAHAHAHAHAHA HAHAHAHAHAHAH AHAHAHAHAHA!!!!! L O L O L O L O L O L O L O L @johnhoford
  130. 130. @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:
  131. 131. @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
  132. 132. @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
  133. 133. @mikescamell • TODO add more videos • Check for todo slides

×