Welcome to another MotionLayout Quickie! This week we'll be exploring MotionLayout sub-elements!

All examples will be based on us using a simple MotionLayout with a start and end state and nothing else.

The old way

Before ConstraintLayout alpha 3, when you were modifying something on a view in the start state and also in the end state you had to define ALL your constraints again to maintain all the previous attributes you had set.

For example, let's say in our start state we had an ImageView and we were going to rotate it 180º in our end state.

Example of using autoComplete

We'd have a MotionScene that might look a little something like this.

<MotionScene>
    
    ...

    <ConstraintSet android:id="@+id/start">

        <Constraint
            android:id="@+id/bookCover"
            android:layout_width="150dp"
            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" />

    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">

        <Constraint
            android:id="@+id/bookCover"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:rotation="180"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
        
    </ConstraintSet>
    
</MotionScene>

That's quite a lot of extra stuff! Especially as all we're going to be doing is rotating our ImageView and not changing our positioning.

A little less conversation

Since ConstraintLayout alpha 3 we've been able to utilise constraint sub-elements which let us only define only the things that are changing. There are 4 types of sub-elements:

  • <Layout>: layout-related attributes e.g. android:layout_height, app:layout_constraintTop_toTopOf
  • <PropertySet>: attributes like alpha, visibility, motionProgress, visibilityMode, constraintTag
  • <Transform>: attributes like scale , rotation, translation, elevation, pivot
  • <Motion>: attributes like motionStagger, pathMotionArc, transitionEasing

Let's use the <Transform> sub-element in our example above.

<MotionScene>
    
    ...

    <ConstraintSet android:id="@+id/start"/>
    
    <ConstraintSet android:id="@+id/end">

        <Constraint android:id="@+id/bookCover">
            <Transform android:rotation="180" />
        </Constraint>

    </ConstraintSet>
    
</MotionScene>

And now it's much smaller! As you can see we can remove all the layout related attributes that we defined before as we don't need to define them. We just rely on the layout attributes that we've already defined in our layout. We don't even need to set anything in our start constraint set as we'll just rely on the View default rotation of 0.

If we want to make something a little more "complex" we can make use of all the sub-elements and produce an ImageView that moves from top to bottom, rotates 180º and moves from 20% alpha to 100% and decelerates as it moves.

<MotionScene>    
    
    ...
    
    <ConstraintSet android:id="@+id/start">

        <Constraint android:id="@+id/bookCover">
            <Layout
                android:layout_width="150dp"
                android:layout_height="wrap_content"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
            <Transform android:rotation="0" />
            <PropertySet android:alpha="0.2"/>
        </Constraint>

    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">

        <Constraint android:id="@+id/bookCover">
            <Layout
                android:layout_width="150dp"
                android:layout_height="wrap_content"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent" />
            <Transform android:rotation="180" />
            <Motion app:transitionEasing="decelerate"/>
            <PropertySet android:alpha="1"/>
        </Constraint>

    </ConstraintSet>
    
</MotionScene>

Example of using autoComplete

And there we have it!

You can find a demo and all the code for this post in the master branch of this repo: https://github.com/mikescamell/Loco-MotionLayout

Is there another feature you like to see in a MotionLayout Quickie? Think I've screwed up? Can you solve a rubik's cube with your tongue?  Let me know on Twitter!

Last but not least, check out androiddev.io for the latest blog posts from Android developers around the world!