Share
Embed
Do the Loco-MotionLayout - droidcon London 2019
A presentation on implementing a crazy dribbble design using MotionLayout.
Michael Scamell
October 24, 2019
Transcript
148 slides
-
– Nicolas Roard (AKA Ruiner of Talks) (AKA THE DEVIL)
“A mix between the property animation framework, layout transitions with TransitionManager, and CoordinatorLayout” MotionLayout -
@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> -
@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> -
@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> -
@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 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> -
@mikescamell Scene 1 - Part 2 <MotionLayout android:layout_width="match_parent" android:layout_height=“match_parent” app:layoutDescription=“@xml/scene1_part2”
> <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 Scene 1 - Part 2 <MotionScene> <Transition android:id="@+id/startToEnd" app:constraintSetStart="@+id/start"
app:constraintSetEnd="@+id/end"> </Transition> </MotionScene> scene_1.xml transition -
@mikescamell <MotionScene> <Transition android:id="@+id/startToEnd" app:constraintSetStart="@+id/start" app:constraintSetEnd="@+id/end"> <OnSwipe app:dragDirection="dragDown" app:onTouchUp="autoComplete" app:touchAnchorId="@id/bookCover"
app:touchAnchorSide="bottom" app:touchRegionId="@id/bookCover" /> </Transition> </MotionScene> Scene 1 - Part 2 scene_1.xml transition -
@mikescamell <MotionScene> <Transition android:id="@+id/startToEnd" app:constraintSetStart="@+id/start" app:constraintSetEnd="@+id/end"> <OnSwipe app:dragDirection="dragDown" app:onTouchUp="autoComplete" app:touchAnchorId="@id/bookCover"
app:touchAnchorSide="bottom" app:touchRegionId="@id/bookCover" /> </Transition> </MotionScene> Scene 1 - Part 2 scene_1.xml transition -
@mikescamell Scene 1 - Part 2 <MotionScene> <Transition android:id="@+id/startToEnd" app:constraintSetStart="@+id/start"
app:constraintSetEnd="@+id/end"> <OnSwipe app:dragDirection="dragDown" app:onTouchUp="autoComplete" app:touchAnchorId="@id/bookCover" app:touchAnchorSide="bottom" app:touchRegionId="@id/bookCover" /> </Transition> </MotionScene> scene_1.xml transition -
@mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/start"> </ConstraintSet> </MotionScene> Scene 1 -
Part 2 scene_1.xml transition constraint_set_start -
@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" android:layout_height="300dp" android:layout_width="wrap_content" /> <Transform android:rotationX="0" android:translationY="0dp" /> </Constraint> </ConstraintSet> … </MotionScene> scene_1.xml transition constraint_set_start -
@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" android:layout_height="300dp" android:layout_width="wrap_content" /> <Transform android:rotationX="0" android:translationY="0dp" /> </Constraint> </ConstraintSet> </MotionScene> scene_1.xml transition constraint_set_start -
@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" android:layout_height="300dp" android:layout_width="wrap_content" /> <Transform android:rotationX="0" android:translationY="0dp" /> </Constraint> </ConstraintSet> </MotionScene> scene_1.xml transition constraint_set_start -
@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" android:layout_height="300dp" android:layout_width="wrap_content" /> <Transform android:rotationX="0" android:translationY="0dp" /> </Constraint> </ConstraintSet> </MotionScene> scene_1.xml transition constraint_set_start -
@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> scene_1.xml transition constraint_set_start -
@mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/bookCover"> <Layout app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
android:layout_height="wrap_content" android:layout_width="150dp" /> <Transform android:rotationX="-55"> </Constraint> </ConstraintSet> </MotionScene> Scene 1 - Part 2 scene_1.xml transition constraint_set_start constraint_set_end -
@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> -
@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" android:layout_height="140dp" android:layout_width="140dp" /> <Transform android:rotationX="-55" /> </Constraint> ... </ConstraintSet> ... </MotionScene> Scene 1 - Part 3 scene_1.xml transition constraint_set_start constraint_set_end -
@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" android:layout_height="140dp" android:layout_width="140dp" /> <Transform android:rotationX="-55" /> </Constraint> ... </ConstraintSet> ... </MotionScene> Scene 1 - Part 3 scene_1.xml transition constraint_set_start constraint_set_end -
@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" android:layout_height="140dp" android:layout_width="140dp" /> <Transform android:rotationX="-55" /> </Constraint> ... </ConstraintSet> ... </MotionScene> Scene 1 - Part 3 scene_1.xml transition constraint_set_start constraint_set_end -
@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" android:layout_height="300dp" android:layout_width="300dp" /> <Transform android:rotationX="0" /> </Constraint> ... </ConstraintSet> </MotionScene> Scene 1 - Part 3 scene_1.xml transition constraint_set_start constraint_set_end -
@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" android:layout_height="300dp" android:layout_width="300dp" /> <Transform android:rotationX="0" /> </Constraint> ... </ConstraintSet> </MotionScene> scene_1.xml transition constraint_set_start constraint_set_end -
@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" android:layout_height="300dp" android:layout_width="300dp" /> <Transform android:rotationX="0" /> </Constraint> ... </ConstraintSet> </MotionScene> scene_1.xml transition constraint_set_start constraint_set_end -
@mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/end"> ... </ConstraintSet> </MotionScene> Scene 1
- Part 3 scene_1.xml transition constraint_set_start constraint_set_end -
@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" android:layout_height="wrap_content" android:layout_width="150dp" /> <Transform android:rotationX="-55" android:translationY="-48dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 1 - Part 3 scene_1.xml transition constraint_set_start constraint_set_end -
@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" android:layout_height="wrap_content" android:layout_width="150dp" /> <Transform android:rotationX="-55" android:translationY="-48dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 1 - Part 3 scene_1.xml transition constraint_set_start constraint_set_end -
@mikescamell Scene 1 - Part 6 • KeyAttribute • KeyPosition
• KeyCycle • KeyTimeCycle • KeyTrigger KeyFrames -
@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 scene_1.xml transition constraint_set_start constraint_set_end -
@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" android:layout_height="300dp" android:layout_width="300dp" /> <Transform android:elevation="4dp" /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 1 scene_2.xml constraint_set_start -
@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" android:layout_height="0dp" android:layout_width="0dp" /> <Transform android:elevation="8dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 2 - Part 1 scene_2.xml constraint_set_start constraint_set_end -
@mikescamell <MotionScene> <Transition android:id="@+id/startToEnd" app:constraintSetEnd="@+id/end" app:constraintSetStart="@+id/start" > </Transition> ... </MotionScene>
Scene 2 - Part 1 scene_2.xml constraint_set_start constraint_set_end transition -
@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> scene_2.xml constraint_set_start constraint_set_end transition -
@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> scene_2.xml constraint_set_start constraint_set_end transition -
@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> scene_2.xml constraint_set_start constraint_set_end transition -
@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> scene_2.xml constraint_set_start constraint_set_end transition -
@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" android:layout_height="0dp" android:layout_width="0dp" /> <Transform android:elevation="8dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 2 - Part 1 scene_2.xml constraint_set_start constraint_set_end transition -
@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" android:layout_height="0dp" android:layout_width="0dp" /> <CustomAttribute app:attributeName="radius" app:customDimension="0dp" /> <Transform android:elevation="8dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 2 - Part 1 scene_2.xml constraint_set_start constraint_set_end transition -
@mikescamell • Integer • Boolean • Float • String •
Dimension • Pixel Dimension • Color • Color Drawable CustomAttribute Scene 2 - Part 1 -
@mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/bookSynopsisCard"> <Layout… /> <Transform
android:elevation="4dp" /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 1 scene_2.xml constraint_set_start constraint_set_end transition -
@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 scene_2.xml constraint_set_start constraint_set_end transition -
@mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/bookSynopsisCard"> <Layout ... />
<Transform android:elevation="8dp" /> </Constraint> </ConstraintSet> </MotionScene> Scene 2 - Part 1 scene_2.xml constraint_set_start constraint_set_end transition -
@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 scene_2.xml constraint_set_start constraint_set_end transition -
@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" android:layout_height="wrap_content" android:layout_width="150dp" /> <Transform android:rotationX="-55" android:translationY="-24dp" /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 2 scene_2.xml constraint_set_start constraint_set_end transition -
@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" android:layout_height="wrap_content" android:layout_width="150dp" /> <Transform android:elevation="4dp" android:rotationX="-55" android:translationY="-24dp" /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 2 scene_2.xml constraint_set_start constraint_set_end transition -
@mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/bookCover"> <Layout ... />
<Transform ... /> </Constraint> </ConstraintSet> ... </MotionScene> Scene 2 - Part 2 scene_2.xml constraint_set_start constraint_set_end transition -
@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 scene_2.xml constraint_set_start constraint_set_end transition -
@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> scene_2.xml constraint_set_start constraint_set_end transition -
@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> scene_2.xml constraint_set_start constraint_set_end transition -
@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> scene_2.xml constraint_set_start constraint_set_end transition -
@mikescamell <MotionScene> <Transition ...> <OnClick ... /> </Transition> ... </MotionScene>
Scene 2 - Part 3 scene_2.xml constraint_set_start constraint_set_end transition -
@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 scene_2.xml constraint_set_start constraint_set_end transition -
@mikescamell <MotionScene> <ConstraintSet android:id="@+id/start"> ... <Constraint android:id="@+id/bookSynopsisTitle"> <Transform android:elevation="4dp" />
<PropertySet android:alpha="1" /> </Constraint> <Constraint android:id="@+id/bookSynopsisText"> <Transform android:elevation="4dp" /> <PropertySet android:alpha="1" /> </Constraint> ... </ConstraintSet> ... </MotionScene> Scene 2 - Part 3 scene_2.xml constraint_set_start constraint_set_end transition -
@mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/bookSynopsisTitle"> <Transform android:elevation="8dp" />
<PropertySet android:alpha="0" /> </Constraint> <Constraint android:id="@+id/bookSynopsisText"> <Transform android:elevation="8dp" /> <PropertySet android:alpha="0" /> </Constraint> ... </ConstraintSet> </MotionScene> Scene 2 - Part 3 scene_2.xml constraint_set_start constraint_set_end transition -
@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> -
@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> -
@mikescamell <MotionScene> <Transition ...> <OnClick ... /> <KeyFrameSet> <KeyAttribute android:alpha="0"
app:framePosition="95" app:motionTarget="@id/bookType" /> ... </KeyFrameSet> </Transition> ... </MotionScene> Scene 2 - Part 4 scene_2.xml constraint_set_start constraint_set_end transition -
@mikescamell <MotionScene> <Transition ...> <OnClick ... /> <KeyFrameSet> <KeyAttribute android:alpha="0"
app:framePosition="95" app:motionTarget="@id/bookType" /> ... </KeyFrameSet> </Transition> ... </MotionScene> Scene 2 - Part 4 scene_2.xml constraint_set_start constraint_set_end transition -
@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 : TransitionAdapter { override fun onTransitionChange( motionLayout: MotionLayout,
startId: Int, endId: Int, progress: Float ) { } }) Scene 2 - Part 4 -
@mikescamell motionLayout.setTransitionListener(object : TransitionAdapter { 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 -
@mikescamell <ConstraintSet android:id="@+id/start"> ... <Constraint android:id="@+id/favourite"> <PropertySet android:alpha="0" /> </Constraint>
<Constraint android:id="@+id/bookmark"> <PropertySet android:alpha="0" /> </Constraint> <Constraint android:id="@+id/readButton"> <PropertySet android:alpha=“0" /> </Constraint> </ConstraintSet> Scene 2 - Part 5 scene_2.xml constraint_set_start constraint_set_end transition -
@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 scene_2.xml constraint_set_start constraint_set_end transition -
@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 scene_2.xml constraint_set_start constraint_set_end transition -
@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 scene_2.xml constraint_set_start constraint_set_end transition -
@mikescamell Scene 2 - Part 6 Start Position End Position
X Y 1.0 1.0 Delta Relative -
@mikescamell Scene 2 - Part 6 X Y 1.0 1.0
End Position Start Position Parent Relative -
@mikescamell Scene 2 - Part 6 X Y 1.0 1.0
End Position Start Position Path Relative -
@mikescamell Scene 2 - Part 6 Start Position End Position
X Y 1.0 1.0 Delta Relative -
@mikescamell Scene 2 - Part 6 Start Position End Position
X Y 1.0 1.0 2.0 Delta Relative -
@mikescamell Scene 2 - Part 6 <KeyPosition app:curveFit="linear" app:framePosition="0" app:keyPositionType="deltaRelative"
app:percentX="1" app:motionTarget="@+id/favourite" /> -
@mikescamell Scene 2 - Part 6 <KeyPosition app:curveFit="linear" app:framePosition="0" app:keyPositionType="deltaRelative"
app:percentX="1" app:motionTarget="@+id/favourite" app:transitionEasing="decelerate" /> -
@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 scene_2.xml constraint_set_start constraint_set_end transition -
@mikescamell Scene 2 - Part 7 <MotionScene> <ConstraintSet android:id="@+id/start"> ...
<Constraint android:id="@+id/bookDetailScrollView"> <PropertySet android:alpha="0" /> <Layout app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="parent" /> </Constraint> </ConstraintSet> ... </MotionScene> scene_2.xml constraint_set_start constraint_set_end transition -
@mikescamell Scene 2 - Part 7 <MotionScene> ... <ConstraintSet android:id="@+id/end">
... <Constraint android:id="@+id/bookDetailScrollView"> <PropertySet android: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> scene_2.xml constraint_set_start constraint_set_end transition -
@mikescamell <MotionScene> <Transition ...> <KeyFrameSet> <KeyAttribute android:alpha="0" app:framePosition="50" app:motionTarget="@id/bookDetailScrollView" />
... </KeyFrameSet> </Transition> ... </MotionScene> Scene 2 - Part 7 scene_2.xml constraint_set_start constraint_set_end transition -
@mikescamell <MotionScene> <Transition android:id="@+id/startToMiddle" app:constraintSetEnd="@+id/middle" app:constraintSetStart="@+id/start" app:duration="1000"> <OnClick app:clickAction="toggle" app:targetId="@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 combined_scene.xml transition_startToMiddle transition_middleToEnd constraint_set_middle constraint_set_end constraint_set_start -
@mikescamell <MotionScene> ... <ConstraintSet android:id="@+id/start" ... /> <ConstraintSet android:id="@+id/middle" ...
/> <ConstraintSet android:id="@+id/end" ... /> </MotionScene> Combined Scene - Part 1,2,3 combined_scene.xml transition_startToMiddle transition_middleToEnd constraint_set_middle constraint_set_end constraint_set_start -
@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 combined_scene.xml transition_startToMiddle transition_middleToEnd constraint_set_middle constraint_set_end constraint_set_start -
@mikescamell Considerations • No GUI • RecyclerView/Lists • It’s in
beta • Performance? • Elevation shadow tweaking is only 28+ -
@mikescamell Considerations • No GUI • RecyclerView/Lists • It’s in
beta • Performance? • Elevation shadow tweaking is only 28+ -
@mikescamell Considerations • No GUI • Doesn’t work with RecyclerViews
(coming soon) • It’s in alpha! • Performance? • Elevation shadow tweaking is only 28+ -
@mikescamell Summary • Start out simple • Use an empty
project • Read the blog posts & ask questions! #motionlayout • Take advantage of Apply Changes • HAVE FUN! -
@mikescamell THANK YOU! Slides: https:/ /speakerdeck.com/mikescamell/do-the-loco- motionlayout-360AnDev-2019 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) -
@mikescamell Links • Slides - https:/ /speakerdeck.com/mikescamell/do-the-loco-motionlayout-360AnDev • Loco-MotionLayout Repo
- https:/ /github.com/mikescamell/Loco-MotionLayout • MotionLayout Blog Posts - https:/ /mikescamell.com/tag/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 -
@mikescamell Links • Google Constraint/MotionLayout Example Repo - https:/ /github.com/googlesamples/android-ConstraintLayoutExamples
• Other Talks - What's New in ConstraintLayout (Google I/O’19) ‣ https:/ /www.youtube.com/watch?v=29gLA90m6Gk - Exploring MotionLayout by Jossi Wolf ‣ https:/ /vimeo.com/333776837 • 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 -
@mikescamell Links • ShapeShifter (Creating AnimatedVectorDrawables) - https:/ /shapeshifter.design/ •
PorterDuff.Mode - https:/ /developer.android.com/reference/android/graphics/PorterDuff.Mode