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

ConstraintLayout 2.0 / MotionLayout

ConstraintLayout 2.0 / MotionLayout

Presentation on MotionLayout at 360 AnDev 2018 in Denver

Nicolas Roard

July 20, 2018
Tweet

More Decks by Nicolas Roard

Other Decks in Programming

Transcript

  1. { 360 | AnDev } 2018 ConstraintLayout 2.0 ★ Layout

    ★ Helpers ★ Rendering ★ Live Resize
  2. { 360 | AnDev } 2018 ConstraintLayout 2.0 ★ Layout

    ★ Helpers ★ Rendering ★ Live Resize ★ Motion
  3. { 360 | AnDev } 2018 ConstraintLayout 2.0 ★ Layout

    ★ Helpers ★ Rendering ★ Live Resize ★ Motion ★ API
  4. { 360 | AnDev } 2018 ConstraintLayout 2.0 ★ Layout

    ★ Helpers ★ Rendering ★ Live Resize ★ Motion ★ API
  5. { 360 | AnDev } 2018 MotionLayout: Why ★ Why

    ★ Audience ★ What can it do
  6. { 360 | AnDev } 2018 Animation Types Animated content

    Transition Layouts Motion Property Animation
  7. { 360 | AnDev } 2018 Animation Types Animated content

    Transition Layouts Motion Lottie, Kyrie, Animated Vector Drawable, GIFs, etc. TransitionManager CoordinatorLayout Property Animation Property animation framework (code)
  8. { 360 | AnDev } 2018 MotionLayout Animated content Transition

    Layouts Motion Lottie, Kyrie, Animated Vector Drawable, GIFs, etc. TransitionManager CoordinatorLayout Property Animation Property animation framework (code)
  9. { 360 | AnDev } 2018 Declarative Approach ★ Better

    & Easier model ★ We can build tooling
  10. { 360 | AnDev } 2018 Declarative Approach ★ Better

    & Easier model ★ We can build tooling
  11. { 360 | AnDev } 2018 Key Concepts ★ Transition

    ★ Events ★ Keyframes ★ Motion
  12. { 360 | AnDev } 2018 ConstraintSet ★ Encapsulate all

    the rules for a layout ★ You can apply ConstraintSet to an existing layout ★ You can switch between multiple ConstraintSets ★ With TransitionManager, basic animation capabilities
  13. { 360 | AnDev } 2018 Start End Seekable Transition

    Start ConstraintSet End ConstraintSet Interpolation
  14. <?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000">

    </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" />
  15. <?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000">

    </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" />
  16. motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000"> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp"

    android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/button" android:layout_width="64dp"
  17. motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000"> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp"

    android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/button" android:layout_width="64dp"
  18. motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000"> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp"

    android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/button" android:layout_width="64dp"
  19. android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/button"

    android:layout_width="64dp" android:layout_height="64dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> </MotionScene>
  20. android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/button"

    android:layout_width="64dp" android:layout_height="64dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> </MotionScene>
  21. android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/button"

    android:layout_width="64dp" android:layout_height="64dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent" /> </ConstraintSet> </MotionScene>
  22. android:layout_height="match_parent"> <View android:id="@+id/button" android:background="@color/colorAccent" android:layout_width="64dp" android:layout_height=“64dp"/> </android.support.constraint.motion.MotionLayout> <Button android:id=“@+id/run" android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:text="Run" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" />
  23. class BasicTransitionActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState) setContentView(R.layout.motion) run.setOnClickListener { motionLayout.transitionToEnd() } } }
  24. <?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000">

    </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent" />
  25. <?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000">

    </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent"
  26. <?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000">

    </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button" android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" motion:layout_constraintBottom_toBottomOf="parent" <OnClick motion:target=“@id/run"/>
  27. xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000"> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/button"

    android:layout_width="64dp" android:layout_height="64dp" android:layout_marginStart="8dp" <OnSwipe motion:dragDirection="dragRight" motion:touchAnchorId="@id/button" motion:touchAnchorSide="right" />
  28. { 360 | AnDev } 2018 MotionLayout XML attributes ★

    app:layoutDescription=”reference” ★ app:applyMotionScene=”boolean” [ default = true ] ★ app:showPaths=”boolean” [ default = false] ★ app:progress=”float” ★ app:currentState=”reference”
  29. { 360 | AnDev } 2018 Interpolated Attributes ★ Position,

    Dimensions ★ Visibility & Alpha ★ Translation, Rotation, Scale, Elevation ★ Custom attributes
  30. { 360 | AnDev } 2018 Custom Attributes ★ Extension

    to ConstraintSet ★ Define values for any attribute ★ Specify the type ★ Specify the setter name string color integer float dimension boolean
  31. { 360 | AnDev } 2018 Utilities ★ MockView ★

    ImageFilterView : Contrast, Saturation, Warmth, Crossfade
  32. <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="1000"> <OnSwipe motion:dragDirection="dragRight" motion:touchAnchorId="@id/image"

    motion:touchAnchorSide="right" /> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/image" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginStart="8dp"
  33. motion:touchAnchorSide="right" /> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/image" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginStart="8dp"

    motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent"> <CustomAttribute motion:attributeName="Crossfade" motion:customFloatValue="0" /> </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint
  34. motion:touchAnchorSide="right" /> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/image" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginStart="8dp"

    motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="parent"> <CustomAttribute motion:attributeName="Crossfade" motion:customFloatValue="0" /> </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint
  35. </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@id/image" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent"

    motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent"> <CustomAttribute motion:attributeName="Crossfade" motion:customFloatValue="1" /> </Constraint> </ConstraintSet> </MotionScene>
  36. </Constraint> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@id/image" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent"

    motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent"> <CustomAttribute motion:attributeName="Crossfade" motion:customFloatValue="1" /> </Constraint> </ConstraintSet> </MotionScene>
  37. { 360 | AnDev } 2018 Transition API ★ transitionToEnd()

    ★ transitionToStart() ★ transitionToState(int state) ★ setProgress(float value) [0 .. 1]
  38. public interface TransitionListener { void onTransitionChange(MotionLayout motionLayout, int startId, int

    endId, float progress); void onTransitionCompleted(MotionLayout motionLayout, int currentId); }
  39. Touch Up / Release Takes in account velocity Choose a

    continuous velocity curve to reach the endpoints with a velocity of zero
  40. Touch Up / Release Takes in account velocity Choose a

    continuous velocity curve to reach the endpoints with a velocity of zero
  41. { 360 | AnDev } 2018 Keyframes ★ Position ★

    Attributes ★ Cycles ★ …and more
  42. KeyAttributes support motion:transitionEasing motion:curveFit android:visibility android:alpha android:elevation android:rotation android:rotationX android:rotationY

    android:scaleX android:scaleY android:translationX android:translationY android:translationZ motion:transitionPathRotate motion:progress + Custom Attributes <CustomAttribute motion:attributeName="BackgroundColor" motion:customColorValue="#D81B60"/>
  43. KeyCycle <KeyFrameSet> <KeyPosition…/> <KeyAttributes…/> <KeyAttributes…/> <KeyCycle motion:target="@+id/widget" motion:framePosition="0" motion:wavePeriod=“0” motion:translationX=“0.0"

    /> <KeyCycle motion:target="@+id/widget" motion:framePosition="50" motion:wavePeriod=“50” motion:translationX=“30dp" /> </KeyFrameSet>
  44. KeyCycle <KeyFrameSet> <KeyPosition…/> <KeyAttributes…/> <KeyAttributes…/> <KeyCycle motion:target="@+id/widget" motion:framePosition="0" motion:wavePeriod=“0” motion:translationX=“0.0"

    /> <KeyCycle motion:target="@+id/widget" motion:framePosition="50" motion:wavePeriod=“50” motion:translationX=“30dp" /> </KeyFrameSet>
  45. KeyCycle <KeyFrameSet> <KeyPosition…/> <KeyAttributes…/> <KeyAttributes…/> <KeyCycle motion:target="@+id/widget" motion:framePosition="0" motion:wavePeriod=“0” motion:translationX=“0.0"

    /> <KeyCycle motion:target="@+id/widget" motion:framePosition="50" motion:wavePeriod=“50” motion:translationX=“30dp" /> </KeyFrameSet>
  46. KeyCycle <KeyFrameSet> <KeyPosition…/> <KeyAttributes…/> <KeyAttributes…/> <KeyCycle motion:target="@+id/widget" motion:framePosition="0" motion:wavePeriod=“0” motion:translationX=“0.0"

    /> <KeyCycle motion:target="@+id/widget" motion:framePosition="50" motion:wavePeriod=“50” motion:translationX=“30dp" /> </KeyFrameSet>
  47. { 360 | AnDev } 2018 Motion ★ CoordinatorLayout ★

    DrawerLayout ★ ViewPager ★ MotionLayout
  48. class CollapsibleToolbar @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null,

    defStyleAttr: Int = 0 ) : MotionLayout(context, attrs, defStyleAttr), AppBarLayout.OnOffsetChangedListener { override fun onOffsetChanged(appBarLayout: AppBarLayout?, verticalOffset: Int) { progress = -verticalOffset / appBarLayout?.totalScrollRange?.toFloat()!! } override fun onAttachedToWindow() { super.onAttachedToWindow() (parent as? AppBarLayout)?.addOnOffsetChangedListener(this) } }
  49. class CollapsibleToolbar @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null,

    defStyleAttr: Int = 0 ) : MotionLayout(context, attrs, defStyleAttr), AppBarLayout.OnOffsetChangedListener { override fun onOffsetChanged(appBarLayout: AppBarLayout?, verticalOffset: Int) { progress = -verticalOffset / appBarLayout?.totalScrollRange?.toFloat()!! } override fun onAttachedToWindow() { super.onAttachedToWindow() (parent as? AppBarLayout)?.addOnOffsetChangedListener(this) } }
  50. <?xml version="1.0" encoding="utf-8"?> <com.google.androidstudio.motionlayoutexample.utils.CollapsibleToolbar xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/motionLayout" app:layoutDescription="@xml/scene_09" android:layout_width="match_parent"

    android:layout_height="match_parent" android:minHeight="50dp" android:fitsSystemWindows="false" app:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed"> <ImageView android:id="@+id/background" android:layout_width="match_parent" android:layout_height="200dp" android:background="@color/colorAccent" android:scaleType="centerCrop"
  51. <ImageView android:id="@+id/background" android:layout_width="match_parent" android:layout_height="200dp" android:background="@color/colorAccent" android:scaleType="centerCrop" android:src="@drawable/monterey"/> <TextView android:id="@+id/label" android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:transformPivotX="0dp" android:transformPivotY="0dp" android:text="Monterey" android:textColor="#FFF" android:textSize="32dp" /> </com.google.androidstudio.motionlayoutexample.utils.CollapsibleToolbar>
  52. <?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" />

    <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/background" android:layout_width="match_parent" android:layout_height="match_parent" android:alpha="1.0" motion:layout_constraintBottom_toBottomOf="parent"/> <Constraint android:id="@+id/label" android:layout_width="wrap_content"
  53. <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/background" android:layout_width="match_parent" android:layout_height="match_parent" android:alpha="1.0" motion:layout_constraintBottom_toBottomOf="parent"/> <Constraint android:id="@+id/label"

    android:layout_width="wrap_content" android:layout_height="wrap_content" android:rotation="-90.0" motion:layout_constraintBottom_toBottomOf="@+id/background" motion:layout_constraintStart_toStartOf="parent"/> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/background"
  54. <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/background" android:layout_width="match_parent" android:layout_height="match_parent" android:alpha="0.2" motion:layout_constraintBottom_toBottomOf="parent"/> <Constraint android:id="@+id/label"

    android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginBottom="8dp" android:rotation="0.0" motion:layout_constraintBottom_toBottomOf="@+id/background" motion:layout_constraintStart_toStartOf="parent" /> </ConstraintSet> </MotionScene>
  55. class DrawerContent @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null,

    defStyleAttr: Int = 0 ) : MotionLayout(context, attrs, defStyleAttr), DrawerLayout.DrawerListener { override fun onDrawerStateChanged(newState: Int) { } override fun onDrawerSlide(drawerView: View, slideOffset: Float) { progress = slideOffset } override fun onDrawerClosed(drawerView: View) { } override fun onDrawerOpened(drawerView: View) { } override fun onAttachedToWindow() { super.onAttachedToWindow() (parent as? DrawerLayout)?.addDrawerListener(this) } }
  56. class DrawerContent @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null,

    defStyleAttr: Int = 0 ) : MotionLayout(context, attrs, defStyleAttr), DrawerLayout.DrawerListener { override fun onDrawerStateChanged(newState: Int) { } override fun onDrawerSlide(drawerView: View, slideOffset: Float) { progress = slideOffset } override fun onDrawerClosed(drawerView: View) { } override fun onDrawerOpened(drawerView: View) { } override fun onAttachedToWindow() { super.onAttachedToWindow() (parent as? DrawerLayout)?.addDrawerListener(this) } }
  57. class DrawerContent @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null,

    defStyleAttr: Int = 0 ) : MotionLayout(context, attrs, defStyleAttr), DrawerLayout.DrawerListener { override fun onDrawerStateChanged(newState: Int) { } override fun onDrawerSlide(drawerView: View, slideOffset: Float) { progress = slideOffset } override fun onDrawerClosed(drawerView: View) { } override fun onDrawerOpened(drawerView: View) { } override fun onAttachedToWindow() { super.onAttachedToWindow() (parent as? DrawerLayout)?.addDrawerListener(this) } }
  58. class ViewpagerHeader @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null,

    defStyleAttr: Int = 0 ) : MotionLayout(context, attrs, defStyleAttr), ViewPager.OnPageChangeListener { override fun onPageScrollStateChanged(state: Int) {} override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { var numPages = 3 progress = (position + positionOffset) / (numPages - 1) } override fun onPageSelected(position: Int) {} }
  59. <android.support.constraint.motion.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" app:layoutDescription="@xml/scene_19"> <include layout="@layout/motion_19_coordination_header" /> <include

    layout="@layout/content_scrolling" /> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_add_a_photo_24dp"/> </android.support.constraint.motion.MotionLayout>
  60. <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetEnd="@+id/end" motion:constraintSetStart="@+id/start" motion:duration="250" motion:interpolator="linear"> <OnSwipe motion:touchAnchorId="@+id/motionLayout"

    motion:touchAnchorSide="bottom" motion:dragDirection="dragUp" /> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@id/motionLayout" android:layout_width="match_parent" android:layout_height="200dp"
  61. motion:touchAnchorSide="bottom" motion:dragDirection="dragUp" /> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@id/motionLayout" android:layout_width="match_parent" android:layout_height="200dp" motion:layout_constraintTop_toTopOf="parent"

    /> <Constraint android:id="@id/scrollable" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintTop_toBottomOf="@+id/motionLayout" /> <Constraint android:id="@id/fab" android:layout_width="wrap_content"
  62. <Constraint android:id="@id/scrollable" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintTop_toBottomOf="@+id/motionLayout" /> <Constraint android:id="@id/fab" android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:visibility="invisible" motion:layout_constraintTop_toBottomOf="parent" motion:layout_constraintRight_toRightOf="parent" android:layout_marginTop="8dp" android:layout_marginRight="8dp"/> </ConstraintSet>
  63. <Constraint android:id="@id/scrollable" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintTop_toBottomOf="@+id/motionLayout" /> <Constraint android:id="@id/fab" android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:visibility="invisible" motion:layout_constraintTop_toBottomOf="parent" motion:layout_constraintRight_toRightOf="parent" android:layout_marginTop="8dp" android:layout_marginRight="8dp"/> </ConstraintSet>
  64. <Constraint android:id="@id/scrollable" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintTop_toBottomOf="@+id/motionLayout" /> <Constraint android:id="@id/fab" android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:visibility="invisible" motion:layout_constraintTop_toBottomOf="parent" motion:layout_constraintRight_toRightOf="parent" android:layout_marginTop="8dp" android:layout_marginRight="8dp"/> </ConstraintSet>
  65. <ConstraintSet android:id="@+id/end"> <Constraint android:id="@id/motionLayout" android:layout_width="match_parent" android:layout_height="56dp" motion:layout_constraintTop_toTopOf="parent" motion:progress="1" /> <Constraint

    android:id="@id/scrollable" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintTop_toBottomOf="@+id/motionLayout" /> <Constraint android:id="@id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content"
  66. <Constraint android:id="@id/scrollable" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintTop_toBottomOf="@+id/motionLayout" /> <Constraint android:id="@id/fab" android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:visibility="visible" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintRight_toRightOf="parent" android:layout_marginBottom="8dp" android:layout_marginRight="8dp" /> </ConstraintSet> </Transition>
  67. <Constraint android:id="@id/scrollable" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintTop_toBottomOf="@+id/motionLayout" /> <Constraint android:id="@id/fab" android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:visibility="visible" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintRight_toRightOf="parent" android:layout_marginBottom="8dp" android:layout_marginRight="8dp" /> </ConstraintSet> </Transition>
  68. <Constraint android:id="@id/scrollable" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintTop_toBottomOf="@+id/motionLayout" /> <Constraint android:id="@id/fab" android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:visibility="visible" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintRight_toRightOf="parent" android:layout_marginBottom="8dp" android:layout_marginRight="8dp" /> </ConstraintSet> </Transition>
  69. { 360 | AnDev } 2018 Documentation ★ Online Documentation:

    https://developer.android.com/reference/android/ support/constraint/motion/package-summary ★ Medium Articles: ★ Introduction to MotionLayout - Part I : http://bit.ly/2O4AmIz ★ Introduction to MotionLayout - Part II : http://bit.ly/2uPuWbw ★ Introduction to MotionLayout - Part III : http://bit.ly/2zRjCSj ★ https://github.com/googlesamples/android-ConstraintLayoutExamples