Introduction to MotionLayout
MotionLayout was introduced in ConstraintLayout 2.0, which brought many new features to Android developers, most notably MotionLayout, a subclass of ConstraintLayout designed to create complex animations and transitions. MotionLayout is a subclass of ConstraintLayout that specializes in creating complex animation effects and transitions. With MotionLayout, developers can define multiple states in a layout file and make smooth transitions between them to realize rich animation effects, such as transitions, expanding and retracting navigation menus, and so on.
ConstraintLayout library upgraded to 2.0+
implementation "androidx.constraintlayout:constraintlayout:2.1.2"
XML root layout replaced with MotionLayout
Way 1: Find the Component Tree in the XML layout, click position 2 and 3 respectively to convert the ConstraintLayout of the root layout to MotionLayout;
Way 2: Of course, it can also be modified manually! ☺
If we pass way 1, AS will automatically create an xml file for us under res/xml/ with MotionScene as the root element:
The documents are listed 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: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>
So how is the MotionScene associated with the MotionLayout? It is associated with the MotionLayout via app:layoutDescription
:
<androidx.constraintlayout.motion.widget.MotionLayout
......
app:layoutDescription="@xml/motion_layout_anim"
app:motionDebug="SHOW_ALL"
app:showPaths="true">
......
</androidx.constraintlayout.motion.widget.MotionLayout >
The relationship between MotionLayout and MotionScene can be represented by the following diagram:
You can see that the MotionLayout has two parts View
and Helper
, where the View part represents the sub-View inside the MotionLayout, MotionLayout is a subclass of ConstraintLayout, so it is a ViewGroup itself; and the Helper part can be considered animation-related, i.e., the XML file associated with the MotionScene as the root element through the attribute inside the MotionLayout. MotionLayout app:layoutDescription
attribute associated with the MotionScene as the root element of the XML file, the next look at the content of the MotionScene.
MotionScene
MotionScene consists of three parts: ConstraintSet, Transition, StateSet, we will go through an example to introduce their respective meanings, the effect diagram:
Let’s look at the corresponding layout file first:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/motion_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/motion_layout_anim"
app:motionDebug="SHOW_ALL"
app:showPaths="true">
<Button
android:id="@+id/btn_clk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:text="click"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible" />
<TextView
android:id="@+id/ll_pop_dialog"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@color/cffd28c"
android:gravity="center"
android:text="Pop Dialog"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_clk" />
</androidx.constraintlayout.motion.widget.MotionLayout>
The layout is simple, id ll_pop_dialog TextView
represents the content to be popped up, which is the part we want to animate, but we don’t see any constraints related to the animation yet, that’s because the constraints are in another file that declares the animation XML (the ConstraintSet declared in MotionScene).
ConstraintSet
A complete animation must contain a starting point and an ending point of the animation, and the ConstraintSet can describe the constraint information of the starting point and the ending point of the animation. It is as follows:
<?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">
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/ll_pop_dialog"
android:layout_width="match_parent"
android:layout_height="200dp"
android:visibility="invisible"
motion:layout_constraintTop_toBottomOf="@+id/btn_clk" />
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/ll_pop_dialog"
android:layout_width="match_parent"
android:layout_height="200dp"
android:visibility="visible"
motion:layout_constraintBottom_toTopOf="@+id/btn_clk">
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#D81B60" />
</Constraint>
</ConstraintSet> </MotionScene>
start represents the start point, end represents the end point, and the internal Constraint represents the constraint information, which establishes the binding relationship with the View in the layout file by means of Id. As described above, at the start point, the popup window content is below the Button button by default; at the end point, it moves to the top of the Button. In addition to the starting point and the end point, how to make the animation move it, it is necessary to use the following Transition conversion.
Transition
Set the Id of the above two ConstraintSet in Transition by constraintSetStart, constraintSetEnd, and trigger the animation by OnClick, OnSwipe:
<?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:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="300">
<KeyFrameSet></KeyFrameSet>
<OnClick
motion:clickAction="toggle"
motion:targetId="@+id/btn_clk"/>
</Transition>
//......
</MotionScene>
constraintSetStart: the corresponding Start state of the ConstraintSet.android:id="@+id/start"
- constraintSetEnd:ConstraintSet,
android:id="@+id/end"
- duration: the duration of the animation.
KeyFrameSet
Already know that ConstraintSet describes the Start, End state, then the path of the animation transition can be a straight line or any curve, and this needs to be set by KeyFrameSet keyframes.
OnClick
Indicates that a user click triggers a transition animation
targetId: specify the id of the View in the layout file, when clicking on the View corresponding to this id will trigger the animation; if you don’t specify the id, then clicking on the whole MotionLayout area will trigger the animation, kind of like PopupWindow set focus=true.
clickAction: you can settransitionToStart、transitionToEnd、toggle、jumpToStart、jumpToEnd
and their respective meanings are as follows:
toggle: default setting, switch back and forth between transitionToStart and transitionToEnd. If it is in Start state, it will switch to End state after clicking, vice versa.
transitionToEnd: transition to End state, with animation effect;
transitionToStart: transition to Start state with animation effect;
jumpToEnd: directly jump to End state, no animation effect;
jumpToStart: directly jump to Start state, no animation effect.
OnSwipe
Triggered by user swipe, it will adjust the progress of the animation according to the user swipe behavior. Multiple OnSwipe can be included under one Transition tag. such as:
<OnSwipe
motion:dragDirection="dragEnd"
motion:touchAnchorId="@+id/btn_clk" />
In the AS control panel, the arrows above start and end are Transitions, and the dot points to OnClick.
If OnSwipe is added, the code is as follows:
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="300">
<OnClick
motion:clickAction="toggle"
motion:targetId="@+id/btn_clk" />
<OnSwipe
motion:dragDirection="dragUp"
motion:touchAnchorId="@+id/btn_clk" />
</Transition>