The preparatory work
It takes three steps to put 🐘 in the fridge, and two to get MotionLayout on your project
Step 1: Upgrade ConstraintLayout to 2.0 and above
implementation 'androidx. Constraintlayout: constraintlayout: 2.0.0 rc1'
Copy the code
At the time of writing, the latest version is 2.0.0-rc1 (2.0.0 is a bit long to develop, the stable version is still 1.1.3).
Step 2: Convert the layout to MotionLayout
ConstraintLayout is a subclass of ConstraintLayout. You can write a layout using ConstraintLayout. You can also use MotionLayout.
ConstraintLayout: Convert it to MotionLayout
Open the layout in the View preview or select ConstraintLayout in the Component Tree and right click on the Covert to MotionLayout option in the menu bar
Get familiar with the MotionLayout workbench
After we convert ConstraintLayout to MotionLayout, we create a MotionScene file in res/ XML /
The file content is as follows
<MotionScene
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
<KeyFrameSet>
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/start">
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
</ConstraintSet>
</MotionScene>
Copy the code
This file is associated with the layout by declaring app:layoutDescription in the layout file
<androidx.constraintlayout.motion.widget.MotionLayout...app:layoutDescription="@xml/activity_main_scene"
>
Copy the code
Looking at the layout,Android Studio (4.0 and above) brought me a visual animation editing tool called MotionLayout, as shown below
**① ** Normal state. After selected, the preview view displays the original state
**② ** indicates ConstraintSet of id=”start”. Select this ConstraintSet and the preview view displays the layout of this ConstraintSet
<ConstraintSet android:id="@+id/start">
</ConstraintSet>
Copy the code
💡 ConstraintSet specifies the position and properties of all views at a certain point in the animation sequence. In general, a Transition element can refer to two ConstraintSet elements, one of which defines the beginning of the animation sequence and the other defines the end of the animation sequence
**③ ** represents the ConstraintSet of id=”end”. When selected, the preview view displays the layout of the ConstraintSet. **④ ** represents the transition from the start ConstraintSet to end
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
</Transition>
Copy the code
**⑤ ** Create a new ConstraintSet **⑥ ** Create a new Transition Transition **⑦ ** Create an action that triggers a Transition, whether it is Click or swipe
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
<! - click - >
<OnClick />
<! Slide -- - >
<OnSwipe />
</Transition>
Copy the code
Look closely at these three ICONS
**⑧ ** there is a tutorial to help
**⑨ ** represents an element of the constraint set
The beginning and end of the animation
Animation has a beginning and an end. We enjoy the process from start to finish.
Get started with a simple effect
preview
Implement a simple rectangle pan animation
💡 The above figure is the running effect, the dotted line in the figure indicates the motion track. To show the dotted line of the motion path you need to set the showPaths property of the MotionLayout to true app:showPaths=”true”
Creating animated elements
Create a View in the layout as follows
<androidx.constraintlayout.motion.widget.MotionLayout...app:layoutDescription="@xml/activity_main_scene"
app:showPaths="true">
<View
android:id="@+id/box"
android:layout_width="64dp"
android:layout_height="64dp"
android:background="@color/colorAccent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
Copy the code
Define the animation start & end state (ConstraintSet)
Add ConstraintSet (id=”box”) to ConstraintSet (id=”start”
This will create a new constraint for View(id=”box”) in the constraint set (id=”start”). The XML code for this wave of operations is as follows
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/box"
android:layout_width="64dp"
android:layout_height="64dp"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent" />
</ConstraintSet>
Copy the code
ConstraintSet is a collection of view constraints and properties. ConstraintSet is described by the Constraint tag. Constraint(id=”box”) Constraint(id=”box”)
<Constraint
android:id="@+id/box"
android:layout_width="64dp"
android:layout_height="64dp"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
Copy the code
ConstraintSet(id=”end”); ConstraintSet(id=”end”); ConstraintSet(id=”end”);
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/box"
android:layout_width="64dp"
android:layout_height="64dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
Copy the code
Transitions (Transition)
View(id=”box”)start and end constraints have been written
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
<! - click - >
<OnClick />
</Transition>
Copy the code
Transition definition visualization is the line with the arrow in the red area in the image above. Notice that there is also a little dot on the line that means clicking
The Transition label, through motion: constraintSetStart specifies the movement state (its value is ConstrainSet id) to motion: constraintSetEnd specified movement end state transitions, Motion :duration to specify how long the animation will be executed. Transition just defines the specified start and end states for the user to trigger ta, and adds or under the Transition tag
💡 Transition has a property motion :autoTransition that sets the behavior of automatically performing transitions without the user having to do so.
OnClick
It is triggered by a user click
attribute
motion:targetId
(id of target View)
If you don’t specify a sub-property, you click the whole screen and if you write this property, you click the View with the corresponding ID to trigger the transition
motion:clickAction
This property can be set to the following values
TransitionToStart Transition to < Transition > element motion: : constraintSetStart attribute specified by the state, Has a transitionToEnd Transition to a state specified by the
OnSwipe
Represents triggered by the user’s slide, which adjusts the progress of the animation based on the user’s slide behavior. A Transition tag can contain multiple OnSwipe. The sample
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
<OnSwipe
motion:dragDirection="dragEnd"
motion:touchRegionId="@+id/box" />
</Transition>
Copy the code
It has the following properties motion:touchAnchorId Which has the value of the View Id, and slides to make the corresponding View
💡 OnSwipe listens for MotionLayout, not Motion :touchAnchorId
Slide to the side of the target view to which you are fixed. MotionLayout will try to maintain a constant distance between the fixed point and the user’s finger. Acceptable values include “left”, “right”, “top”, and “bottom”. Motion :dragDirection Direction of the user’s sliding action. If this property is set, this
will only apply to slides in a particular direction. Acceptable values include “dragLeft”, “dragRight”, “dragUp”, and “dragDown”.
This is an interesting property, because you can make the target follow the direction of your finger, you can go in the opposite direction of your finger, or you can go in the vertical direction of your finger, depending on how you set this property, right
Motion :dragScale controls how far the view moves relative to the sliding length. The default value is 1, indicating that the view should move the same distance as the slide distance. If the dragScale is less than 1, the view will move much less than the slide distance (for example, a dragScale of 0.5 means that if the slide moves 4 centimeters, the target view will move 2 centimeters). If the dragScale is greater than 1, the view will move farther than the slide distance (for example, a dragScale of 1.5 means that if the slide moves 4 cm, the target view will move 6 cm). Motion :maxVelocity The maximum speed of the target view. When the finger slides a certain speed, the target View will continue to run in inertia, accelerating and then slowing down (default). If the motion accelerates to the maximum we set (according to our junior high school physics knowledge, can reach the maximum velocity, depending on the acceleration (aaa), time (TTT), and the initial velocity (v0v_0v0), v=v0+ ATV =v_0+ ATV =v0+ AT), then it is accelerated first. It’s moving at its maximum speed, and then it’s slowing down. Motion :maxAcceleration Specifies the maximum acceleration of the target View. If you want the View to move faster, you need to increase the acceleration
Property transition animation
ConstraintSet specifies constraints and properties. In the translation example above, we only used constraints. Let’s see what happens when we add attributes.
1. Set the transparency attribute
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/box"
android:layout_width="64dp"
android:layout_height="64dp"
android:alpha="1"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/box"
android:layout_width="64dp"
android:layout_height="64dp"
android:alpha="0.1"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
</ConstraintSet>
Copy the code
Set at the start position of the animationandroid:alpha="1"
End Position SettingAndroid: alpha = "0.1"
MotionLayout will automatically overdo it for us, and it will look like this
2. Set a rotation attribute
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/box"
android:layout_width="64dp"
android:layout_height="64dp"
android:rotationX="0"... The constraints are as above />
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/box"
android:layout_width="64dp"
android:layout_height="64dp"... The constraints are as above />
</ConstraintSet>
Copy the code
Set at the start position of the animationandroid:rotationX="0"
Android :rotationX=”0″
You can also change other properties to try, such as setting different background color, setting different size, etc
Animation of the movement process 🏃
The animation above is an animation where we define the start and end states and then it transitions itself. So let’s talk about if we interfere in the course of his movement
Key frames (KeyFrameSet)
KeyFrameSet is a child of Transition
By default, we only need to define the start and end states of the animation, and MotionLayout will smooth the transition. If I want to do a more complicated motion, I need the KeyFrameSet to set it up, so we set certain constraints or properties at certain points in the motion of the animation, the transitions between the points, the MotionLayout will also help us smooth the transitions.
KeyFrameSet can contain KeyPosition, KeyAttribute, KeyCycle, KeyTimeCycle, and KeyTrigger, which can be added by editing, as shown in the following figure
If we click select (1), there will be a timeline tool. If we click play (2), we can preview the animation in the editor. If we click eat (3), we can see the option to add children to the KeyFrameSet
KeyPosition
You can change the position of the animation as it moves.
So the movements we’ve done up here are straight lines, and now I’m going to do curve movements with KeyPosition
The diamond points in the figure are the ones we modified with KeyPosition, as shown below
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="1000">
<OnClick motion:targetId="@id/box"/>
<KeyFrameSet>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/box"
motion:keyPositionType="parentRelative"
motion:percentY="0.3"
motion:percentX="0.8"/>
</KeyFrameSet>
</Transition>
Copy the code
Added several attributes to KeyPosition abovemotion:framePosition
Indicates the progress of the animation. The value range is [0,100]. The 50 above indicates 50% of the animation progress.motion:motionTarget
Indicates the view ID of the path to be modifiedmotion:keyPositionType
Represents the coordinate system type. The value can be parentRelative, pathRelative or deltaRelativemotion:percentY
和 motion:percentX
It’s the ratio of the vertical to the horizontal relative to the frame of reference.
Let’s focus on keyPositionType
1.parentRelative
Motion :percentX=”0.8″; motion:percentY=”0.3″; motion:percentY=”0.3″
I have drawn two figures above, as we said above (0.3,0.8) should be the two grey focal points of Figure 1, but we found that Figure 1 is a little bit different from the actual point. When we specify a point with KeyPosition, we specify the center point of the view. Figure 1 is ideal, and if our view is infinitesimally small, that’s what happens in Figure 1. In fact, our view cannot be infinitesimally small, and the real situation should look like figure 2.
2.deltaRelative
In this type, the starting point coordinate of the view is (0,0) and the end point coordinate is (1,1), as shown in the diagram
<KeyFrameSet>
<KeyPosition
motion:framePosition="50"
motion:motionTarget="@id/box"
motion:keyPositionType="deltaRelative"
motion:percentY="0.5"
motion:percentX="0.8"
/>
</KeyFrameSet>
Copy the code
This time deliberately move the end point of the view to the upper right corner, otherwise the starting position and the end position will be on the same level as defined above, and the X and Y axes will coincide in deltaRelative.
3.pathRelative
This is interesting, the starting point (0,0) is still the starting point of the view, and the ending point of the view is (1,0), so the frame is set up as follows
The positive Y axis is 90 degrees clockwise on the X axis, which is exactly the same as the View coordinate system in Android, which is the opposite of what we’re learning.
KeyAttribute
KeyAttribute allows us to change the attribute at a certain point in the animation process.
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="2000">
<OnClick motion:targetId="@id/box"/>
<KeyFrameSet>
<KeyAttribute
motion:framePosition="50"
motion:motionTarget="@id/box"
android:rotationY="180"
android:alpha="0"
/>
</KeyFrameSet>
</Transition>
Copy the code
We added a KeyAttribute to the KeyFrameSet and specified the attribute Android :rotationY=”180″, which works like this
You can see that the view rotates from 0 to 180 along Y, and then from 180 to 0 again, and the transparent animation proceeds from 1 to 0, and then from 0 to 1.
You can also try to change the actual property values and try it out.
KeyAttibute defines a View native to Android, Android: Visibility, Android :alpha, Android: Elevation, Android: Rotation, Android :rotationX, Android :rotationY, Android :scaleX, Android :scaleY, Android :translationX, Android :translationY, Android :translationZ You can use the CustomAttribute, a child of KeyAttibute
<KeyFrameSet>
<KeyAttribute
android:rotationY="180"
motion:framePosition="50"
motion:motionTarget="@id/box">
<CustomAttribute
motion:attributeName="rectangleColor"
motion:customColorValue="@color/colorAccent" />
</KeyAttribute>
</KeyFrameSet>
Copy the code
CustomAttribute specifies two attributes. AttributeName specifies the name of the CustomAttribute. The value of the attribute can be color, integer, float, string, size, or Boolean. So you use the Motion :customColorValue property to specify its value.
KeyCycle
You can have the view change its property values periodically during the animation process according to some periodic functions
The above example is to change the Android :translationY property periodically during the animation [0%,80%] with the period function sin
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="2000">
<OnClick />
<KeyFrameSet>
<KeyCycle
motion:framePosition="80"
motion:motionTarget="@+id/box"
motion:wavePeriod="1"
motion:waveShape="sin"
android:translationY="50dp"/>
</KeyFrameSet>
</Transition>
Copy the code
Motion :framePosition=”80″ means KeyCycle extends to 80% of the animation, motion:wavePeriod means number of cycles in motion, motion:waveShape means type of cycle, this is specified as sin, It’s going to be a sine periodic function.
KeyTimeCycle
According to some periodic functions on the key frame, its attribute value is changed periodically, and the effect is shown in the following figure
So you can see KeyTimeCycle compared to KeyCycle, KeyTimeCycle cycles on frames, KeyCycle cycles during the animation
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="2000">
<OnClick />
<KeyFrameSet>
<KeyTimeCycle
motion:motionTarget="@+id/box"
motion:wavePeriod="1"
android:translationY="50dp"
/>
</KeyFrameSet>
</Transition>
Copy the code
The parameters are similar to KeyCycle. If we specify the number of periods of motion:wavePeriod, the change frequency will be faster.
KeyTrigger
In this class, we define two public functions who() and where(), as follows (the simplest custom View 😄).
class MyTextView(context: Context? , attrs: AttributeSet?) : AppCompatTextView(context, attrs) {fun who(a) {
text = Who am I?
}
fun where(a) {
text = "There I am."}}Copy the code
The layout code is as follows
<? xml version="1.0" encoding="utf-8"? > <androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"... > <View android:id="@+id/box"... /> <com.wkk.motionlayoutdemo.MyTextView android:id="@+id/myTextView"... /> </androidx.constraintlayout.motion.widget.MotionLayout>Copy the code
MotionScene core code
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="2000">
<OnClick />
<KeyFrameSet>
<KeyTrigger
motion:framePosition="20"
motion:motionTarget="@id/myTextView"
motion:onCross="who" />
<KeyTrigger
motion:framePosition="80"
motion:motionTarget="@id/myTextView"
motion:onCross="where" />
</KeyFrameSet>
</Transition>
Copy the code
FramePosition The progress of the animation, motionTarget the target of action, Motion :onCross the name of the function to fire
OnCross is an animation, whether it’s forward or backward, and it executes as soon as it reaches the set framePosition. Two other functions are also fired. OnPositiveCross will only execute if the forward animation reaches the set framePosition. The opposite is true of onNegativeCros.
The above definition is to trigger the view whose ID is myTextView at 20% of the animation progresswho
Method to trigger the myTextView view when the animation progress is 80%where
Method, which works as follows.
Write in the last
MotionLayout can help us achieve a lot of animation effects, it has been out for a long time, it should be very likely to release a stable version, it is time to learn a wave, the above is my study of MotionLayout record some knowledge points, there are a lot of knowledge points of MotionLayout, The above is just a simple demonstration of some properties, but more practice is needed to achieve complex animations. MotionLayout has a very good editor, at the beginning of learning XML is not too good to write, you can use graphical editing tools to click, see what it helps us to generate XML is like, I also pasted some reference links for learning, MotionLayout together to learn.
Advanced article
MotionLayout Instruction manual (advanced + Actual combat)
Refer to the link
MotionLayout official documentation MotionLayout/ConstraintLayout official sample (making) using MotionLayout for Android applications to add animation MotionLayout (Codelab) API