Search code examples
androidandroid-jetpackandroid-motionlayout

How to define a common interpolator for all transitions of a MotionScene?


I have three states in a given layout, and I'd like to have the same interpolator used for any transition between these states. How can I define (either in XML or code) the same interpolator for all transitions without having to repeat myself as below?

<?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/state_a"
        motion:constraintSetEnd="@id/state_b"
        motion:motionInterpolator="easeOut"
        motion:duration="250"/>

    <Transition
        motion:constraintSetStart="@id/state_a"
        motion:constraintSetEnd="@id/state_c"
        motion:motionInterpolator="easeOut"
        motion:duration="250"/>

    <Transition
        motion:constraintSetStart="@id/state_b"
        motion:constraintSetEnd="@id/state_c"
        motion:motionInterpolator="easeOut"
        motion:duration="250"/>

    <ConstraintSet android:id="@+id/state_a">...</ConstraintSet>
    <ConstraintSet android:id="@+id/state_b">...</ConstraintSet>
    <ConstraintSet android:id="@+id/state_c">...</ConstraintSet>

</MotionScene>

Solution

  • This is how to define an interpolator or duration common to all three Transitions:

    <?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:motionInterpolator="easeOut"
            motion:duration="250" />
    
        <Transition
            motion:constraintSetStart="@id/state_a"
            motion:constraintSetEnd="@id/state_b" />
    
        <Transition
            motion:constraintSetStart="@id/state_a"
            motion:constraintSetEnd="@id/state_c" />
    
        <Transition
            motion:constraintSetStart="@id/state_b"
            motion:constraintSetEnd="@id/state_c" />
    
        <ConstraintSet android:id="@+id/state_a">...</ConstraintSet>
        <ConstraintSet android:id="@+id/state_b">...</ConstraintSet>
        <ConstraintSet android:id="@+id/state_c">...</ConstraintSet>
    
    </MotionScene>
    

    Looking at the current MotionLayout source (v2.0.1), Transition elements that don't specify neither constraintSetStart nor constraintSetEnd are considered abstract, and its attributes become default to all Transitions in the MotionScene.

    public static class Transition {
        private boolean mIsAbstract = false;
        private int mConstraintSetEnd = -1;
        private int mConstraintSetStart = -1;
        // ...
    
        // This constructor creates a Transition based on another Transition
        Transition(MotionScene motionScene, MotionScene.Transition global) {
            if (global != null) {
                this.mDefaultInterpolator = global.mDefaultInterpolator;
                this.mDuration = global.mDuration;
                // ...
            }
        }
    
        private void fill(MotionScene motionScene, Context context, TypedArray a) {
            // Parse attributes from TypedArray, constraintSetStart being one of them
            if (this.mConstraintSetStart == -1) {
                this.mIsAbstract = true;
            }
        }
    
        // ...
    }
    

    When a Transition in the MotionScene is fully abstract (no start or end specified), it becomes the mDefaultTransition:

    public class MotionScene {
        private MotionScene.Transition mDefaultTransition = null;
        private ArrayList<MotionScene.Transition> mAbstractTransitionList = new ArrayList();
        // ...
    }
    

    It works as I described, but there isn't any reference to this in the current documentation. Unfortunately, I can't link to the source, because the latest versions are not available in AOSP (see this issue). The only way of seeing this code is through IntelliJ's decompiler. EDIT: Links from @hoford's answer

    This possibility was first mentioned in the release notes of beta4. Source available at https://github.com/androidx/constraintlayout.