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>
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.