I have recently tried the MotionLayout, I works fine on a button when it is a direct child of the MotionLayout but the same motion scene does not work,  when I enclose the button in another layout, bu the parent layout is still MotionLayout.
First layout where the button is direct child :-
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  app:layoutDescription="@xml/demo"
  android:layout_height="match_parent"
  tools:context=".Demo" >
  <Button
    android:layout_width="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:layout_height="wrap_content"
    android:id="@+id/yellow_button"
     />
  </androidx.constraintlayout.motion.widget.MotionLayout>
Second layout where button is indirect child :-
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
app:layoutDescription="@xml/demo"
android:layout_height="match_parent"
tools:context=".Demo"
>
<LinearLayout
   android:layout_width="match_parent"
   android:id="@+id/l1"
   app:layout_constraintBottom_toBottomOf="parent"
   app:layout_constraintEnd_toEndOf="parent"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toTopOf="parent"
   android:layout_height="wrap_content">
  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/yellow_button"/>
 </LinearLayout>
</androidx.constraintlayout.motion.widget.MotionLayout>
The motion scene layout is below:-
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ConstraintSet android:id="@+id/start">
    <Constraint android:id="@+id/yellow_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" >
        <CustomAttribute app:attributeName="alpha"
            app:customFloatValue="0.0"/>
    </Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
    <Constraint android:id="@id/yellow_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:alpha="1.0"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        >
        <CustomAttribute app:attributeName="alpha"
            app:customFloatValue="1.0"/>
    </Constraint>
</ConstraintSet>
<Transition
    app:constraintSetEnd="@id/end"
    app:autoTransition="animateToEnd"
    app:constraintSetStart="@+id/start"
    app:duration="2000"/>
Is there any guideline that needs to be followed in these cases??
OR
Does this mean that only direct children of the MotionLayout can be animated with it?
This medium article (https://medium.com/google-developers/introduction-to-motionlayout-part-i-29208674b10d) by Google Developers says under the 'Limitations' section: "MotionLayout will only provide its capabilities for its direct children — contrary to TransitionManager, which can work with nested layout hierarchies as well as Activity transitions."
I found out a way to make it works, it involves a few lines of code and I have not tried it with so complex MotionLayouts but at least for a typically beautiful nested XML it works like a charm.
Check out this animation example:
<androidx.constraintlayout.motion.widget.MotionLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/activity_main_scene"
tools:context=".MainActivity">
<androidx.constraintlayout.motion.widget.MotionLayout
    android:id="@+id/header_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layoutDescription="@xml/header_container_scene"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:contentDescription="@string/header_background"
        android:foreground="@drawable/white_gradient"
        android:scaleType="centerCrop"
        android:src="@drawable/tonitan_unsplash"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <ImageView
        android:id="@+id/logo"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:layout_marginTop="12dp"
        android:contentDescription="@string/logo"
        android:scaleType="centerCrop"
        android:src="@drawable/ic_launcher_foreground"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <androidx.constraintlayout.motion.widget.MotionLayout
        android:id="@+id/child_header_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp"
        app:layoutDescription="@xml/child_header_container_scene"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/logo">
        <TextView
            android:id="@+id/header_text_1"
            style="@style/Title.White"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_header"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
        <TextView
            android:id="@+id/header_text_2"
            style="@style/Title.White"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/header_value"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="1.0"
            app:layout_constraintStart_toEndOf="@id/header_text_1"
            app:layout_constraintTop_toTopOf="parent" />
        <TextView
            android:id="@+id/another_text_1"
            style="@style/Title.White"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="12dp"
            android:text="@string/my_subtitle"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/header_text_1" />
        <TextView
            android:id="@+id/another_text_2"
            style="@style/Title.White"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="12dp"
            android:text="@string/subtitle_value"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="1.0"
            app:layout_constraintStart_toEndOf="@id/another_text_1"
            app:layout_constraintTop_toBottomOf="@id/header_text_1" />
    </androidx.constraintlayout.motion.widget.MotionLayout>
</androidx.constraintlayout.motion.widget.MotionLayout>
<TextView
    android:id="@+id/my_app_title"
    style="@style/Title.Black.25"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginStart="16dp"
    android:layout_marginTop="12dp"
    android:layout_marginEnd="16dp"
    android:text="@string/my_title"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/header_container" />
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_marginTop="12dp"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/my_app_title"
    tools:listitem="@layout/rv_item" />
</androidx.constraintlayout.motion.widget.MotionLayout>
As you can see in above XML, there are three scenes: activity_main_scene, header_container_scene, child_header_container_scene. Each one will take care about its direct children and the only missing thing is synch them up:
private fun setUpMotionLayoutListener() = with(binding) {
        rootContainer.setTransitionListener(this@MainActivity)
        headerContainer.setTransitionListener(this@MainActivity)
        childHeaderContainer.setTransitionListener(this@MainActivity)
    }
private fun updateNestedMotionLayout(motionLayout: MotionLayout?) = motionLayout?.let {
        with(binding) {
            if (it.id == rootContainer.id) {
                headerContainer.progress = it.progress
                childHeaderContainer.progress = it.progress
            }
        }
    }
And that's all!
The complete example can be found here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With