motionlayout
什么是MotionLayout? (What Is MotionLayout?)
MotionLayout
is a subclass of ConstraintLayout
that includes all of its outstanding features, and it’s fully declarative with the capability to implement complicated transitions in the XML. It is backward-compatible with API level 14, which means it covers 99% of use cases.
MotionLayout
是ConstraintLayout
的子类,它包含所有出色的功能,并且完全声明了XML的功能。 它与API级别14向后兼容,这意味着它涵盖了99%的用例。
The new MotionLayout editor in Android Studio 4.0 makes it easy to work with MotionLayout
. It provides a fancy environment to implement transitions, MotionScenes
, and more.
Android Studio 4.0中新的MotionLayout编辑器使使用MotionLayout
变得容易。 它提供了一个精美的环境来实现转场, MotionScenes
等。
为什么我们需要MotionLayout? (Why Do We Need MotionLayout?)
Implementing animations in Android is a complicated thing. We have various APIs, such as View Animations, Object Animator, Animated Vector Drawables, Transitions, and more. Sometimes, developers get confused about where to use which API. This is where MotionLayout
comes handy.
在Android中实现动画是一件复杂的事情。 我们有各种API,例如“查看动画”,“对象动画师”,“可绘制矢量动画”,“过渡”等。 有时,开发人员会对在哪里使用哪个API感到困惑。 这是MotionLayout
派上用场的地方。
MotionLayout
is a new and effective way to implement transitions in Android. It acts as a bridge between the layout transitions and complex motion handling, providing a mix of features among the property animation framework, TransitionManager, and CoordinatorLayout.
MotionLayout
是在Android中实现过渡的一种新的有效方法。 它充当布局过渡和复杂运动处理之间的桥梁,在属性动画框架 , TransitionManager和CoordinatorLayout之间提供了多种功能。
MotionLayout
is intended to resize, move, and animate UI elements. However, it has a few limitations:
MotionLayout
旨在调整UI元素的大小,移动和设置动画。 但是,它有一些限制:
It only supports animating
MotionLayout
's direct children.它仅支持对
MotionLayout
的直接子项进行动画MotionLayout
。- We can’t implement activity transitions. 我们无法实现活动转换。
术语 (Terminology)
There are a few terms we need to learn before using MotionLayout
.
在使用MotionLayout
之前,我们需要学习一些术语。
运动场景 (MotionScene)
A MotionScene
is an XML resource in the project that is used to write motion descriptions for each MotionLayout
. This XML file starts with a MotionScene
tag and contains all the necessary information related to the motions in that layout.
MotionScene
是项目中的XML资源,用于为每个MotionLayout
编写运动描述。 该XML文件以MotionScene
标记开头,并包含与该布局中的动作有关的所有必要信息。
约束集 (ConstraintSet)
ConstraintSet
is an XML tag that we use inside MotionScene
to describe each endpoint of our motion. We can create as many ConstraintSets
as we want based on the requirement.
ConstraintSet
是一个XML标签,我们在MotionScene
内部使用它来描述运动的每个端点。 我们可以根据需求创建任意数量的ConstraintSets
。
约束 (Constraint)
Constraint
is another XML tag that we use inside ConstraintSet
. This is where we can use all the features of ConstraintLayout
. On each endpoint of the motion, we can use this tag to set the view based on transition.
Constraint
是我们在ConstraintSet
内部使用的另一个XML标记。 在这里我们可以使用ConstraintLayout
所有功能。 在运动的每个端点上,我们都可以使用此标记基于过渡设置视图。
过渡 (Transition)
Transition
is an XML tag that defines the motion between two ConstraintSets
using the constraintSetStart
and constraintSetEnd
attributes. We can also mention the duration of the transition using this attribute. Along with these basic things, we can do the actual transition-related code here.
Transition
是一个XML标记,它使用constraintSetStart
和constraintSetEnd
属性定义了两个ConstraintSets
之间的运动。 我们也可以使用此属性提及过渡的持续时间。 除了这些基本内容,我们还可以在此处执行与转换相关的实际代码。
You will learn more about this tag in the later sections of this article.
您将在本文的后续部分中了解有关此标记的更多信息。
关键帧集 (KeyFrameSet)
It is used to specify the location and attributes of the views throughout the motion. With this sturdy XML tag, we can implement complex transitions. The attributes like KeyPosition
and KeyAttribute
are used to enforce transitions on the views at a particular moment.
它用于指定整个运动中视图的位置和属性。 有了这个坚固的XML标签,我们可以实现复杂的转换。 诸如KeyPosition
和KeyAttribute
类的属性用于在特定时刻对视图强制执行过渡。
To better understand how all these tags and attributes connect, let’s create a simple MotionScene
. Have a look:
为了更好地理解所有这些标签和属性如何连接,让我们创建一个简单的MotionScene
。 看一看:
<?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/button"
android:layout_width="60dp"
android:layout_height="60dp"
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/button"
android:layout_width="60dp"
android:layout_height="60dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000">
// This is where all the keyframe and other things were implemented.
</Transition>
</MotionScene>
layoutDescription (layoutDescription)
This is an attribute that we use in Motionlayout
to link the MotionScene
XML resource file.
这是我们在Motionlayout
使用的属性,用于链接MotionScene
XML资源文件。
显示路径 (showpaths)
This attribute is used to enable debug mode during transitions. It comes in handy once you get familiar with MotionLayout
.
此属性用于在过渡期间启用调试模式。 一旦熟悉MotionLayout
它就会派上用场。
Let’s create a simple piece of code showing how to use these attributes:
让我们创建一个简单的代码片段,展示如何使用这些属性:
<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/motionLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/scene_01"
tools:showPaths="true"
>
...
</androidx.constraintlayout.motion.widget.MotionLayout>
这个怎么运作 (How It Works)
Before diving into the implementation, it’s essential to learn how it works while doing the transitions as a beginner.
在深入研究实现之前,必须以入门者的身份学习它的工作原理。
First, we need to create a layout file with MotionLayout
as the root tag. Always remember that Motionlayout
can only animate its direct children. Nested hierarchy transitions won’t work with MotionLayout
.
首先,我们需要创建一个以MotionLayout
为根标签的布局文件。 永远记住, Motionlayout
只能为其直接子对象设置动画。 嵌套的层次结构过渡不适用于MotionLayout
。
Then we need to implement the actual layout with all the views. Once it is finished, we need to create a MotionScene
resource file under the res/xml
folder to define the necessary motions.
然后,我们需要使用所有视图来实现实际的布局。 完成后,我们需要在res/xml
文件夹下创建一个MotionScene
资源文件,以定义必要的动作。
The MotionScene
XML file is the core part of implementing the transitions. We can create as many endpoints as we like using the ConstraintSet
tag and apply transitions between them using the Transition
tag.
MotionScene
XML文件是实现过渡的核心部分。 我们可以使用ConstraintSet
标签创建任意数量的端点,并使用Transition
标签在端点之间应用过渡。
Once you’re done with the MotionScene
file, link it with the actual layout using the layoutDescription
attribute. That’s all we need to do. To better understand it, let’s implement a Twitter splash screen animation with MotionLayout
.
一旦完成了MotionScene
文件,就可以使用layoutDescription
属性将其与实际布局链接。 这就是我们要做的。 为了更好地理解它,让我们使用MotionLayout
实现Twitter初始屏幕动画。
积分 (Integration)
As I said, MotionLayout
is a subclass of ConstraintLayout
, so we don’t need to integrate a new library. We need to update the version of ConstraintLayout
. At the time of writing, the latest release is 2.0.0-beta6
, but always make sure that you’re using the latest version.
如我所说, MotionLayout
是ConstraintLayout
的子类,因此我们不需要集成新的库。 我们需要更新ConstraintLayout
的版本。 在撰写本文时,最新版本是2.0.0-beta6
,但是请始终确保您使用的是最新版本。
dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta6'
}
Twitter用MotionLayout飞溅动画 (Twitter Splash Animation With MotionLayout)
创建一个简单的Twitter初始布局 (Creating a simple Twitter splash layout)
As the first step, we need to create a layout file with the MotionLayout
root tag. Have a look at the layout file:
第一步,我们需要使用MotionLayout
根标记创建一个布局文件。 看一下布局文件:
<?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:layout_width="match_parent"
android:layout_height="match_parent"
>
</androidx.constraintlayout.motion.widget.MotionLayout>
The next step is to create the views. Here, it is a simple ImageView
with a Twitter icon aligned at the center of the screen. We need to apply the Twitter theme color as the background to the root tag. Have a look:
下一步是创建视图。 在这里,它是一个简单的ImageView
,其Twitter图标对准屏幕中心。 我们需要将Twitter主题颜色作为背景应用于根标签。 看一看:
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#2f95fe"
>
<ImageView
android:id="@+id/imageView2"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/ic_twitter_icon"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.motion.widget.MotionLayout>
实施MotionScene (Implementing MotionScene)
Now that we’re done with the layout implementation, it’s time to create a MotionScene
. Before we start implementing, let’s be clear about what we’re trying to achieve. Have a look:
现在我们已经完成了布局实现,是时候创建一个MotionScene
。 在开始实施之前,让我们先弄清楚我们要实现的目标。 看一看:
If we look at the transition carefully, we can see there are two animations:
如果我们仔细看一下过渡,我们可以看到有两个动画:
- First, the Twitter icon scales down a bit. 首先,Twitter图标会缩小一点。
- After a moment, it scales to full screen. 片刻之后,它将缩放到全屏。
We now need to create a MotionScene
XML file under res/xml
with the name twitter_motion_scene
. Have a look:
现在,我们需要在res/xml
下创建一个名称为twitter_motion_scene
的MotionScene
XML文件。 看一看:
<?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">
</MotionScene>
Now, we need endpoints to create a transition. We can create the endpoints of the motion using the ConstrainSet
tag. In the first set, we need to mention the placement of the Twitter icon, as we want it at the center. In the second set, we don’t need to do anything. Have a look:
现在,我们需要端点来创建过渡。 我们可以使用ConstrainSet
标记创建运动的端点。 在第一组中,我们需要提及Twitter图标的位置,因为我们希望它位于中心位置。 在第二组中,我们不需要执行任何操作。 看一看:
<ConstraintSet
android:id="@+id/start">
<Constraint
android:layout_width="100dp"
android:layout_height="100dp"
android:id="@+id/imageView"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent"
/>
</ConstraintSet>
<ConstraintSet android:id="@+id/end"
>
The id
attribute in the MotionScene
indicates the view in the layout.
MotionScene
的id
属性指示布局中的视图。
Now, we have two endpoints in which we can animate the views. It’s time to create a transition between the ConstraintSets
. First, we need to mention start and endpoints using the constraintSetStart
and constraintSetEnd
attributes, respectively.
现在,我们有两个端点可以在其中创建视图动画。 现在该在ConstraintSets
之间创建过渡了。 首先,我们需要分别使用constraintSetStart
和constraintSetEnd
属性提及起点和终点。
Then we need to scale the Twitter icon a bit smaller than the original size. After a moment, we need to scale it back to standard size. Finally, it should scale to full screen. To implement this, we used KeyFrameSet
and KeyAttribute
. Have a look:
然后,我们需要缩放Twitter图标,使其比原始大小小一点。 片刻之后,我们需要将其缩放回标准大小。 最后,它应该缩放到全屏。 为了实现这一点,我们使用了KeyFrameSet
和KeyAttribute
。 看一看:
<Transition
android:id="@+id/transition"
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:autoTransition="animateToEnd">
<KeyFrameSet >
<KeyAttribute
motion:motionTarget="@+id/imageView"
motion:framePosition="20"
android:scaleX="0.7"
android:scaleY="0.7" />
<KeyAttribute
motion:motionTarget="@+id/imageView"
motion:framePosition="50"
android:scaleX="1.0"
android:scaleY="1.0" />
<KeyAttribute
motion:motionTarget="@+id/imageView"
motion:framePosition="100"
android:scaleX="15.0"
android:scaleY="15.0"
android:alpha="0.1"/>
</KeyFrameSet>
</Transition>
Here, we have three KeyAttributes
to scale the icon down, bring it back to standard size, and finally scale it to full screen. framePosition
is the key attribute and that is when the appropriate scaling should happen.
在这里,我们有三个KeyAttributes
来缩小图标,将其恢复为标准大小,最后将其缩放为全屏。 framePosition
是关键属性,也就是应该进行适当缩放的时间。
When we put everything together, it looks like this:
当我们将所有内容放在一起时,它看起来像这样:
<?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:layout_width="100dp"
android:layout_height="100dp"
android:id="@+id/imageView"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintBottom_toBottomOf="parent"
/>
</ConstraintSet>
<ConstraintSet android:id="@+id/end"
>
</ConstraintSet>
<Transition
android:id="@+id/transition"
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:autoTransition="animateToEnd">
<KeyFrameSet >
<KeyAttribute
motion:motionTarget="@+id/imageView"
motion:framePosition="20"
android:scaleX="0.7"
android:scaleY="0.7" />
<KeyAttribute
motion:motionTarget="@+id/imageView"
motion:framePosition="50"
android:scaleX="1.0"
android:scaleY="1.0" />
<KeyAttribute
motion:motionTarget="@+id/imageView"
motion:framePosition="100"
android:scaleX="15.0"
android:scaleY="15.0"
android:alpha="0.1"/>
</KeyFrameSet>
</Transition>
</MotionScene>
将MotionScene与布局文件链接 (Linking MotionScene with the layout file)
To wrap up, we need to link the MotionScene
with the layout file. We can do this by using the layoutDescription
attribute in the MotionLayout
node. Have a look:
最后,我们需要将MotionScene
与布局文件链接。 我们可以通过使用MotionLayout
节点中的layoutDescription
属性来执行此操作。 看一看:
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#2f95fe"
app:layoutDescription="@xml/twitter_animation_layout_scene">
<ImageView
android:id="@+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/ic_twitter_icon"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.motion.widget.MotionLayout>
观察过渡状态 (Observe transition status)
It’s almost done, but there’s one thing left: After the completion of the transition, we have to navigate to another activity. To implement this, we need to add a listener to observe MotionLayout’
s transition status.
差不多完成了,但是还有一件事:过渡完成后,我们必须导航到另一个活动。 为了实现这一点,我们需要添加一个侦听器以观察MotionLayout'
的过渡状态。
MotionLayout
supports this out of the box. We need to use setTransitionListener
on the MotionLayout
. In the onTransitionCompleted
callback, we need to invoke the code to navigate. Have a look:
MotionLayout
支持此功能。 我们需要在MotionLayout
上使用setTransitionListener
。 在onTransitionCompleted
回调中,我们需要调用代码进行导航。 看一看:
motionlayout?.setTransitionListener(object : MotionLayout.TransitionListener {
override fun onTransitionCompleted(p0: MotionLayout?, p1: Int) {
startActivity(Intent(this@MainActivity, SecondActivity::class.java))
finish()
}
override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) { }
override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) { }
override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) { }
})
结论 (Conclusion)
Feel free to play around with this on GitHub.
可以在GitHub上随意使用它。
To learn more about advanced Android development, read the following articles:
要了解有关高级Android开发的更多信息,请阅读以下文章:
That is all for now. I hope you learned something useful. Thanks for reading.
到此为止。 我希望你学到了一些有用的东西。 谢谢阅读。
翻译自: https://medium.com/better-programming/beginners-guide-to-motion-layout-732395a7de7e
motionlayout