The original link

Define the motion path in MotionLayout

introduce

MotionLayout is a new animation-focused layout from ConstraintLayout 2.0. The previous articles in this series provided a good overview of this system. I highly recommend that you check them out before reading this article.

  • Introduction to MotionLayout (part I)
  • Custom Attributes, Image Transitions, KeyFrames (Part II)
  • Taking advantage of MotionLayout in Your Existing Layouts (CoordinatorLayout, DrawerLayout, ViewPager) (Part III)

The MotionLayout animation system works by inserting values (usually the position/size of the control) between the two states, which are specified using ConstraintLayout’s constraint sets and view properties. Transitions between these two states can also be driven entirely by touch events. This system will usually provide a good result for your transition.

In addition to the states described above, MotionLayout also supports keyframes, which were introduced briefly in Part 2 of this series, and which we’ll cover in depth in this article. Note that while keyframes are good, they are definitely a more specialized tool; You may not need it or use it occasionally.

Keep in mind that animations added to your app should have a purpose; Don’t abuse it!

However, if you need to add extra functionality to your transition effects, keyframes can help you extend the functionality of MotionLayout. As you can see, there’s a lot to cover here:

  • Key frames Keyframes
  • Position Keyframe Position Keyframes
  • Arc Motion
  • Time model Easing
  • Attributes Keyframes
  • Cycle Keyframes & TimeCycle Keyframes (which we will cover in Part V)

Start key frame (a rendez-vous in Time)

At a high level, keyframes can make a modification to the interpolation between your two states.

MotionLayout supports different keyframes:

  • Position keyframe:KeyPosition
  • Attribute Keyframe Attribute KeyFrame:KeyAttribute
  • Cycle keyframe:KeyCycle
  • TimeCycle KeyFrame:KeyTimeCycle

Note that each type of keyframe is independent of the others — that is, you don’t need to define all keyframes at the same point (but you can’t define multiple keyframes of the same type at the same point)

General properties

All keyframes (position, property, loop, period) have some key common properties:

  • nodemotion:framePosition: Timing of keyframes in transition (from 0 to 100)
  • The targetmotion:target: Which object is affected by the keyframe
  • interpolatormotion:transitionEasing: Which interpolator to use (linear by default)
  • Curve fittingmotion:curveFit: Spline (default) or line – which curve to use to fit keyframes. The default is monotone spline, which makes the transition smoother, but of course you can decide to use linear fitting.

Position keyframe

Location keyframes are probably the most common ones you’ll use. It allows you to modify the path of controls on the screen during transitions. For example, let’s animate one of the controls in MotionLayout:

We have an initial state (bottom left) and an ending state (top right). The transition process is linear interpoltion motion of a control between these two states.

By introducing position keyframes, we can turn the motion path into a curvilinear motion:

Adding more keyframes allows you to create complex motion paths.

<KeyFrameSet>
    <KeyPosition
        motion:keyPositionType="pathRelative"
        motion:percentX="0.75"
        motion:percentY="0.3"
        motion:framePosition="25"
        motion:target="@id/button"/>
    <KeyPosition
        motion:keyPositionType="pathRelative"
        motion:percentY="0.4"
        motion:framePosition="50"
        motion:target="@id/button"/>
    <KeyPosition
        motion:keyPositionType="pathRelative"
        motion:percentX="0.25"
        motion:percentY="0.3"
        motion:framePosition="75"
        motion:target="@id/button"/>
</KeyFrameSet>
Copy the code

What are position keyframes?

If ConstraintSets already allow you to place controls in a very flexible way, you may be asking yourself what is the point of positioning keyframes. Here’s why:

  • Keyframes represent temporary modifications, and ConstraintSets represent resting
  • Keyframes are much lighter in calculation than ConstraintSet
  • Position keyframes allow you to manipulate the path of a control — ConstraintSets specifies the position of a control relative to another control.

Note: It is possible to define multiple ConstraintSets in a MotionScene, so if you have a multi-step action where the steps are in a valid “rest” state, then you can use them instead of keyframes. State-to-state transitions must be done in code (change listeners can be used).

Using XML representation

Keyframes exist in the

property, and

in the
MotionScene file, and contain at least:

  • target: a control affected by a keyframe
  • framePosition: Keyframe usage time, (0-100)
  • keyPositionType: The coordinate system usedRelative container (parentRelative), Triangulation (deltaRelative), Relative path (pathRelative)
  • percentX / percentY: The (x,y) coordinates of the position
<Transition .>
    <KeyFrameSet>
        <KeyPosition
            motion:keyPositionType="parentRelative"
            motion:percentY="0.25"
            motion:framePosition="50"
            motion:target="@+id/button"/>
    </KeyFrameSet>
</Transition>
Copy the code

Different coordinate system

The start and end states in MotionLayout allow for complex positioning. For ConstraintSets, they can use all the functionality of ConstraintLayout. The system will correctly process these states according to density, screen orientation, language and other changes.

For keyframes to work in such a system, we need them to be able to be laid out in a similarly adaptive way — rather than simply using fixed positions.

In order to solve this problem and keep the key frame system lightweight, we propose a flexible method — in a given coordinate system, the position of each key frame is expressed by (x,y) coordinate pair (pair) :

  • Motion: percentX = "float" >"
  • Motion: percentY = "float" >"

The meaning of this coordinate depends on the type of coordinate system used: parentRelative, deltaRelative, or pathRelative.

Note: The position of each keyframe exists independently — each keyframe’s position can be represented by its own relative coordinate system.

parentRelative

Coordinates are represented relative to the parent container. This is a very direct and intuitive way to express the position of a keyframe and is usually sufficient. Typically, you use it to do a wide range of motions associated with the parent container.

Because this coordinate system is based only on the parent container dimension, and not on the start/end position of the moving control, you might encounter situations where the last keyframe position ends in a suboptimal position (relative to the start/end position). (the original: you may encounter situations where the resulting keyframe position ends in a suboptimal position (relative to the The start/end positions).)

deltaRelative

The second coordinate system solves this problem by using the start/end position definition. The coordinates represent the percentage between the beginning and the end.

A little bit like the parent container coordinate system, this is a relatively straightforward coordinate system, and it generally gives good results. This is useful when you want a control to start or end in horizontal or vertical motion.

It has a potential problem — because it is defined by the difference between the start and end positions of the controls, the keyframe will not change on the corresponding axis if the difference is very small (or none). For example, if the control moves from left to right on the screen and stays at the same height, using Deltarelative percentY on the location keyframe will have no effect.

Relative path

The last coordinate system defines a straight path relative to the starting state to the ending state. It solves the problem in deltaRelative coordinates – using pathRelative allows positional keyframes to be set off-path when a control is not moving on the vertical axis. Notice that it also supports negative coordinates. It is a more special coordinate system, but especially useful for processing time. Here is an example of implementing a curve shape (such as an “S” shape) that will remain the same even if the endpoints change.

Arc Motion

A typical type of motion used in Material Design is arc motion. One way to create an arc motion using MotionLayout is to add properly placed position keyframes between the start and end positions, as described in the previous section.

In ConstraintLayout 2.0.0 Alpha 2, we’ve introduced a new approach to perfect circular motion — and it’s much easier to use. Simply add the Motion :pathMotionArc attribute to the initial ConstraintSet to switch the default Linear Motion to Arc Motion.

Let’s look at a simple example where the starting state is at the bottom right of the screen and the ending position is at the top of the screen and horizontally centered. Add the following property to create an arc motion:

Motion: startHorizontal pathMotionArc = ""

If the property is changed to:

Motion: startVertical pathMotionArc = ""

Will change the direction of the arc:

You can still use position keyframes to create more complex arcs. Here are the results:

It is done by adding a vertical centered position keyframe to the animation:

<KeyPosition
    motion:keyPositionType="parentRelative"
    motion:percentY="0.5"
    motion:framePosition="50"
    motion:target="@id/button"/>
Copy the code

You can also use keyframes in this scene to change the direction of the arc by setting the Motion :pathMotionArc property. The property can be flip (flip the current arc direction), None (revert to linear motion), startHorizontal or startVertical.

<KeyPosition
    motion:keyPositionType="parentRelative"
    motion:pathMotionArc="flip"
    motion:percentY="0.5"
    motion:framePosition="50"
    motion:target="@id/button"/>
Copy the code

<KeyPosition
    motion:keyPositionType="parentRelative"
    motion:pathMotionArc="none"
    motion:percentY="0.5"
    motion:framePosition="50"
    motion:target="@id/button"/>
Copy the code

Time modeling (Easing)

In the previous sections, we introduced various mechanisms to help you define a movement path. For an animation, it’s not just about choosing the right path; Time is also of the essence.

Since position keyframes can be specified by time, you can use them to define how fast or slow the control moves, depending on how much space it moves.

But within a single fragment — between the start and end states, or between key frames — the time interpolator is linear. (the time interpolation is linear)

You can use the Motion :transitionEasing property to specify an easing curve to modify it. You can use this attribute in ConstraintSets or keyframes, and it accepts these values:

  • cubic(float, float , float, float)X1,y1,x2,y2 represent the control points of a cubic bezier equation from 0,0 to 1,1
  • Or use keywords:standard.accelerate.decelerate, the predefined curve is similarMaterial Design definitions.

Standard easing

Usually used in non-touch driven animations. It works best with elements that start and end in a static state.

Acceleration curve (Accelerate easing)

Acceleration is usually used to move an element off the screen.

Decelerating curve. Decelerating curve.

Deceleration is usually used when an element enters the screen.

Key Attributes

Property keyframes allow you to specify changes in a control’s property at a given point in time during animation — in other words, they are similar to position keyframes, but act on properties rather than positions.

The above example is implemented by adding the KeyAttribute element to the MotionScene file:

<KeyFrameSet>
    <KeyAttribute
        android:scaleX="2"
        android:scaleY="2"
        android:rotation="- 45"
        motion:framePosition="50"
        motion:target="@id/button" />
</KeyFrameSet>
Copy the code

Instead of KeyPostion, we need to specify the framePosition (when the keyframe is applied) and the target (which object is affected).

Supported properties

Some View properties you can use out of the box:

android:visibility, android:alpha, android:elevation, android:rotation, android:rotationX, android:rotationY, android:scaleX, android:scaleY, android:translationX, android:translationY, android:translationZ

Focus on

Restricted by the SDK level of the application, some of these properties will not work:

  • SDK 21 introducedandroid:elevation
  • SDK 21 introducedandroid:translationZ

Custom Attributes

You can declare custom attributes in ConstraintSets and KeyAttribute nodes by adding a

child node. This node requires an attributeName, which is the name of the getter/setter (minus the set/get prefix) and the value type to be passed in or used. The attribute type is specified as one of the following:

  • customColorValue: color value
  • customColorDrawableValue: Color value Drawable
  • customIntegerValue : Integer
  • customFloatValue : Float
  • customStringValue : String
  • customDimensionSize:
  • customBoolean : Boolean

For example, this side is the XML corresponding to the animation above:

<ConstraintSet android:id="@+id/start">
    <Constraint
        android:id="@+id/button" .>
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#D81B60"/>
    </Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
    <Constraint
        android:id="@+id/button" .>
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#9999FF"/>
    </Constraint>
</ConstraintSet>
Copy the code

conclusion

This article introduced the most common keyframe and path specifications in MotionLayout. We’ll discuss cycles (KeyCycle) and cycles (KeyTimeCycle) in Part 5 of this series, which introduce a very powerful way to add disturbances (wave-like) to properties (path-based or time-based), Allows for a variety of interesting but predictable looping effects (bounce, shaking, pulsations, etc.).

Various examples using MotionLayout can be viewed at ConstraintLayout Examples Github Repository.