Skip to content

MotionEffect

Nicolas Roard edited this page Jul 31, 2021 · 17 revisions

MotionEffect is a new motion helper in 2.1 let you automatically add keyframes to the views it references, depending on their overall movement direction. It can simplifies a lot creating well crafted transitions.

To better understand where this is useful, take the following example:

The default transition between the two states do a linear interpolation -- the result is confusing and not pleasant.

If we look at this example, we can identify elements that are moving west only (2, 3, 6, 9), and others moving in a different pattern (1, 4, 5, 7, 8):

We can use MotionEffect to apply a fade effect to those elements, giving a much more pleasant result:

You can look at this example to see it in action:

<androidx.constraintlayout.motion.widget.MotionLayout ... >
    <TextView android:id="@+id/t1" ... />
    <TextView android:id="@+id/t2" ... />
    <TextView android:id="@+id/t3" ... />
    <TextView android:id="@+id/t4" ... />
    <TextView android:id="@+id/t5" ... />
    <TextView android:id="@+id/t6" ... />
    <TextView android:id="@+id/t7" ... />
    <TextView android:id="@+id/t8" ... />
    <TextView android:id="@+id/t9" ... />
   
    ...
  
    <androidx.constraintlayout.helper.widget.MotionEffect
        android:id="@+id/fade"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:constraint_referenced_ids="t1,t2,t3,t4,t5,t6,t7,t8,t9"
    />
</androidx.constraintlayout.motion.widget.MotionLayout>    

Controling which views get the effect

First, only the views referenced in the MotionEffect will possibly get the effect applied to them.

Secondly, by default, we automatically compute the main direction of movement of those views (between North, South, East, West), and only the views that are moving opposite to that direction will get the effect applied to them.

Using motionEffect_move=auto|north|south|east|west you can override this to specify which direction you want the effect to apply to.

You can also make this apply strictly (or not) to elements doing this motion with motionEffect_strict=true|false.

Default effect

By default the effect will apply a fade out / fade in; you can control the amount of alpha as well as the start/end of the effect with the following attributes:

    app:motionEffect_start="keyframe"
    app:motionEffect_end="keyframe"

You can control the amount of alpha and translation in (x,y) to apply (see this example):

app:motionEffect_alpha="alpha"
app:motionEffect_translationX="dimension"
app:motionEffect_translationX="dimension"

Custom effect

You can also reference a ViewTransition to apply to the widgets instead of the default fade effect, simply by setting motionEffect_viewTransition, giving you unlimited control on the type of effect you want to apply.

For example, to get the following animation:

You can create a new ViewTransition and reference it in your MotionEffect:

in your layout xml:

    <androidx.constraintlayout.helper.widget.MotionEffect
    ...
    app:motionEffect_viewTransition="@+id/coolFade"/>

in your motion scene:

    <ViewTransition android:id="@+id/coolFade">
        <KeyFrameSet>
            <KeyAttribute
                motion:framePosition="20"
                android:scaleX="0.1"
                android:scaleY="0.1"
                android:rotation="-90"
                android:alpha="0" />
            <KeyAttribute
                motion:framePosition="80"
                android:scaleX="0.1"
                android:scaleY="0.1"
                android:rotation="-90"
                android:alpha="0" />
        </KeyFrameSet>
    </ViewTransition>