Android MotionLayout motionStaggered
Android MotionLayout motionStaggered
我试图让我的视图使用 MotionLayout 进行动画处理,但希望某些约束在其他约束之前进行动画处理。我认为这是 motion:staggered 属性 for Transition 的目的,但我不明白它是如何工作的,也没有它在任何地方成功工作的例子。对于 MotionLayout 的更新版本,似乎我们应该为单个约束设置 motion:motionStagger,但我似乎无法让它按需要错开。我能找到的唯一文档是 here 解释增强交错 API 但我不明白如何使用它。
我在下面添加了我的 MotionLayout 代码。作为参考,我使用的是 2.0.0-beta3'
版本的 ConstraintLayout
<?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"
motion:motionInterpolator="easeInOut"
motion:staggered="0.4" />
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@id/translucentOverlay">
<Layout
android:layout_width="5dp"
android:layout_height="5dp"
motion:layout_constraintBottom_toBottomOf="@id/imageBorder"
motion:layout_constraintEnd_toEndOf="@id/imageBorder"
motion:layout_constraintStart_toStartOf="@id/imageBorder"
motion:layout_constraintTop_toTopOf="@id/imageBorder" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0.0" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/imageBorder">
<Layout
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<CustomAttribute
motion:attributeName="crossfade"
motion:customFloatValue="0" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/imageBackground">
<Layout
android:layout_width="32dp"
android:layout_height="32dp"
motion:layout_constraintBottom_toBottomOf="@id/imageBorder"
motion:layout_constraintEnd_toEndOf="@id/imageBorder"
motion:layout_constraintStart_toStartOf="@id/imageBorder"
motion:layout_constraintTop_toTopOf="@id/imageBorder" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/profileInitialText">
<Layout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintBottom_toBottomOf="@id/imageBackground"
motion:layout_constraintEnd_toEndOf="@id/imageBackground"
motion:layout_constraintStart_toStartOf="@id/imageBackground"
motion:layout_constraintTop_toTopOf="@id/imageBackground" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1.0" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/profileImage">
<Layout
android:layout_width="32dp"
android:layout_height="32dp"
motion:layout_constraintBottom_toBottomOf="@id/imageBackground"
motion:layout_constraintEnd_toEndOf="@id/imageBackground"
motion:layout_constraintStart_toStartOf="@id/imageBackground"
motion:layout_constraintTop_toTopOf="@id/imageBackground" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/name">
<Layout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="128dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0.0" />
<Motion motion:motionStagger="5" />
</Constraint>
<Constraint android:id="@id/description">
<Layout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/name" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0.0" />
<Motion motion:motionStagger="5" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@id/translucentOverlay">
<Layout
android:layout_width="match_parent"
android:layout_height="match_parent" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1.0" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/imageBorder">
<Layout
android:layout_width="88dp"
android:layout_height="88dp"
motion:layout_constraintBottom_toBottomOf="@id/imageBackground"
motion:layout_constraintEnd_toEndOf="@id/imageBackground"
motion:layout_constraintStart_toStartOf="@id/imageBackground"
motion:layout_constraintTop_toTopOf="@id/imageBackground" />
<CustomAttribute
motion:attributeName="crossfade"
motion:customFloatValue="1" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/imageBackground">
<Layout
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginTop="64dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/profileInitialText">
<Layout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintBottom_toBottomOf="@id/imageBackground"
motion:layout_constraintEnd_toEndOf="@id/imageBackground"
motion:layout_constraintStart_toStartOf="@id/imageBackground"
motion:layout_constraintTop_toTopOf="@id/imageBackground" />
<Motion motion:motionStagger="2" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0.0" />
</Constraint>
<Constraint android:id="@id/profileImage">
<Layout
android:layout_width="70dp"
android:layout_height="70dp"
motion:layout_constraintBottom_toBottomOf="@id/imageBackground"
motion:layout_constraintEnd_toEndOf="@id/imageBackground"
motion:layout_constraintStart_toStartOf="@id/imageBackground"
motion:layout_constraintTop_toTopOf="@id/imageBackground" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/name">
<Layout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/profileImage" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1.0" />
<Motion motion:motionStagger="5" />
</Constraint>
<Constraint android:id="@id/description">
<Layout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/name" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1.0" />
<Motion motion:motionStagger="5" />
</Constraint>
</ConstraintSet>
交错的实际数学可能有点令人困惑,但在实践中
交错
每个动画视图都被赋予一个 Stager 值 (app:motionStagger)
默认情况下,视图的交错值是与视图列表中最顶层视图的曼哈顿距离。您可以通过属性手动设置值
这会为每个标记有 motionStagger 的视图分配一个浮点交错值(未标记的视图将被忽略)。首先启动具有最低浮点值 (V0) 的视图。最后启动具有最高浮点值 (Vn) 的视图。
- 对于交错值 S(Vi) 的任何视图
- 随着 TS 的过渡交错值(从 0.0 - 1.0)
- 动画时长为duration
- 观看动画时长DS = duration * (1 -TS)
- 调用交错分数 SFi = (S(Vi) - S(V0)) / (S(Vn) - S(V0))
- 视图开始动画:(duration-DS) * SFi
这个数学运算可能令人困惑。所以一个实际的例子
如果我有 3 个视图 View1、View2、View3,我将 motionStagger 分别设置为 2、5 和 7,并将动画持续时间设置为 5 秒。
当我将过渡交错设置为 0.4 时,进度如下:
The animation duration is 3.0 sec = 5 * (1- 0.4)
View1 stagger fraction = 0 = (2-2)/(7-2)
View1 starts at 0.0 sec
View1 end at 3.0 sec (0.0 + 3.0)
View2 stagger fraction = 0.6 = (5-2)/(7-2)
View2 starts at 1.2 sec (5.0-3.0) * 0.6
View2 ends at 4.2 sec 1.2 + 3.0
View3 stagger fraction = 1
View3 starts at 2.0 sec (5.0 - 3.0) * 1
View3 ends at 5.0 sec
好的,所以在弄乱了很长时间,反复试验,研究了 this 发布更新中给出的方程式之后,这就是我想出的。
上面的链接文章给了我们一些令人困惑的方程式
Let
The motionStagger value is S(Vi)
The overall stagger value is stagger (from 0.0 - 1.0)
The duration of the animation is duration
The views animation duration = duration * (1 - stagger)
The view starts animating at duration * (stagger - stagger * (S(Vi) - S(V0)) / (S(Vn) - S(V0)))
确定过渡交错值:
要确定您希望整体错开的程度,请考虑您尝试错开的观看次数。
我上面链接的文章指出 viewDuration = totalDuration*(1 - stagger)
所以我们可以重新排列这个等式成为 stagger = 1 - (viewDuration / totalDuration)
。在我的例子中,因为我希望在视图进入时有三个不同的时刻,所以我希望我的 viewDuration / totalDuration
大约是 1/3
。为了简化数学运算,我选择将我的交错设置为 0.6
,使每个 viewDuration 为 400。所以我的转换代码如下所示
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@+id/start"
motion:duration="1000"
motion:motionInterpolator="easeInOut"
motion:staggered="0.6" />
你会注意到我将持续时间增加到 1000 以更清楚地看到交错(一旦你计算出你的交错值,这里的持续时间可以更新并且交错应该适当地缩放以适应时间范围) .
确定个人观点交错值:
所以现在我们需要弄清楚将什么作为 ?在 <Motion motion:motionStagger="?" />
这是数学变得非常复杂的地方。对于我们要设置交错的每个视图,它们应该按交错值排序。我们得到的等式(修改后比文章更具可读性)是:
animationStartTime = totalDuration * (stagger - stagger * ((staggerCurrentView - lowestStaggerValue)/(highestStaggerValue - lowestStaggerValue))
这确实有点复杂,但我可以用我的例子来分解它。
所以对于我的示例,我们已经讨论了我如何让三个视图稍微均匀地交错(这就是为什么我们选择 0.6 的交错值)。根据下面等式的逆结构,我知道具有最高 motionStagger
值的视图将首先进行动画处理。
假设我们有三个视图,一个我想排在第一位的 ImageView,一个我想排在第二位的 TextView,以及一个我想排在第三位的 Button。所以我将给 ImageView 分配一个 motionStagger 值 3,为 TextView 分配一个 motionStagger 值 2,为 TextView 分配一个 motionStagger 值 1。让我们在这里进行计算:
Stagger value = 0.6
motionStaggerValues = 3 (for ImageView), 2 (for TextView), and 1(for Button)
ImageView animationStartTime = 1000 * (0.6 - 0.6 * ((3-1)/(3-1)))
= 1000 * (0.6 - 0.6 * (1)) = 1000 * 0 = 0
所以ImageView从0开始动画,动画持续400ms(如上一节所示)。
现在让我们计算 TextView
Stagger value = 0.6
motionStaggerValues = 3 (for ImageView), 2 (for TextView), and 1(for Button)
TextView animationStartTime = 1000 * (0.6 - 0.6 * ((2-1)/(3-1)))
= 1000 * (0.6 - 0.6 * (1/2)) = 1000 * 0.3 = 300
所以 TextView 在 300 开始动画并持续 400 毫秒。
最后,让我们计算一下按钮的开始时间:
Stagger value = 0.6
motionStaggerValues = 3 (for ImageView), 2 (for TextView), and 1(for Button)
TextView animationStartTime = 1000 * (0.6 - 0.6 * ((1-1)/(3-1)))
= 1000 * (0.6 - 0.6 * (0)) = 1000 * 0.6 = 600
所以按钮从 600 开始动画并持续 400 毫秒。
这些值可以根据您选择的 motionStagger 值进行移动和交错。为了解释起见,我试图让它尽可能简单,但它可能会变得非常复杂,具体取决于您要完成的任务。这是我上面概述的示例的最终代码的样子。
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@id/imageView">
...
<Motion motion:motionStagger="3" />
</Constraint>
<Constraint android:id="@id/textView">
...
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/button">
...
<Motion motion:motionStagger="1" />
</Constraint>
</ConstraintSet>
您将需要另一个并行 ConstraintSet
作为结束状态。
我试图让我的视图使用 MotionLayout 进行动画处理,但希望某些约束在其他约束之前进行动画处理。我认为这是 motion:staggered 属性 for Transition 的目的,但我不明白它是如何工作的,也没有它在任何地方成功工作的例子。对于 MotionLayout 的更新版本,似乎我们应该为单个约束设置 motion:motionStagger,但我似乎无法让它按需要错开。我能找到的唯一文档是 here 解释增强交错 API 但我不明白如何使用它。
我在下面添加了我的 MotionLayout 代码。作为参考,我使用的是 2.0.0-beta3'
版本的 ConstraintLayout
<?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"
motion:motionInterpolator="easeInOut"
motion:staggered="0.4" />
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@id/translucentOverlay">
<Layout
android:layout_width="5dp"
android:layout_height="5dp"
motion:layout_constraintBottom_toBottomOf="@id/imageBorder"
motion:layout_constraintEnd_toEndOf="@id/imageBorder"
motion:layout_constraintStart_toStartOf="@id/imageBorder"
motion:layout_constraintTop_toTopOf="@id/imageBorder" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0.0" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/imageBorder">
<Layout
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<CustomAttribute
motion:attributeName="crossfade"
motion:customFloatValue="0" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/imageBackground">
<Layout
android:layout_width="32dp"
android:layout_height="32dp"
motion:layout_constraintBottom_toBottomOf="@id/imageBorder"
motion:layout_constraintEnd_toEndOf="@id/imageBorder"
motion:layout_constraintStart_toStartOf="@id/imageBorder"
motion:layout_constraintTop_toTopOf="@id/imageBorder" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/profileInitialText">
<Layout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintBottom_toBottomOf="@id/imageBackground"
motion:layout_constraintEnd_toEndOf="@id/imageBackground"
motion:layout_constraintStart_toStartOf="@id/imageBackground"
motion:layout_constraintTop_toTopOf="@id/imageBackground" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1.0" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/profileImage">
<Layout
android:layout_width="32dp"
android:layout_height="32dp"
motion:layout_constraintBottom_toBottomOf="@id/imageBackground"
motion:layout_constraintEnd_toEndOf="@id/imageBackground"
motion:layout_constraintStart_toStartOf="@id/imageBackground"
motion:layout_constraintTop_toTopOf="@id/imageBackground" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/name">
<Layout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="128dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0.0" />
<Motion motion:motionStagger="5" />
</Constraint>
<Constraint android:id="@id/description">
<Layout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/name" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0.0" />
<Motion motion:motionStagger="5" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@id/translucentOverlay">
<Layout
android:layout_width="match_parent"
android:layout_height="match_parent" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1.0" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/imageBorder">
<Layout
android:layout_width="88dp"
android:layout_height="88dp"
motion:layout_constraintBottom_toBottomOf="@id/imageBackground"
motion:layout_constraintEnd_toEndOf="@id/imageBackground"
motion:layout_constraintStart_toStartOf="@id/imageBackground"
motion:layout_constraintTop_toTopOf="@id/imageBackground" />
<CustomAttribute
motion:attributeName="crossfade"
motion:customFloatValue="1" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/imageBackground">
<Layout
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_marginTop="64dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/profileInitialText">
<Layout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
motion:layout_constraintBottom_toBottomOf="@id/imageBackground"
motion:layout_constraintEnd_toEndOf="@id/imageBackground"
motion:layout_constraintStart_toStartOf="@id/imageBackground"
motion:layout_constraintTop_toTopOf="@id/imageBackground" />
<Motion motion:motionStagger="2" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0.0" />
</Constraint>
<Constraint android:id="@id/profileImage">
<Layout
android:layout_width="70dp"
android:layout_height="70dp"
motion:layout_constraintBottom_toBottomOf="@id/imageBackground"
motion:layout_constraintEnd_toEndOf="@id/imageBackground"
motion:layout_constraintStart_toStartOf="@id/imageBackground"
motion:layout_constraintTop_toTopOf="@id/imageBackground" />
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/name">
<Layout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/profileImage" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1.0" />
<Motion motion:motionStagger="5" />
</Constraint>
<Constraint android:id="@id/description">
<Layout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toBottomOf="@id/name" />
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1.0" />
<Motion motion:motionStagger="5" />
</Constraint>
</ConstraintSet>
交错的实际数学可能有点令人困惑,但在实践中
交错
每个动画视图都被赋予一个 Stager 值 (app:motionStagger) 默认情况下,视图的交错值是与视图列表中最顶层视图的曼哈顿距离。您可以通过属性手动设置值
这会为每个标记有 motionStagger 的视图分配一个浮点交错值(未标记的视图将被忽略)。首先启动具有最低浮点值 (V0) 的视图。最后启动具有最高浮点值 (Vn) 的视图。
- 对于交错值 S(Vi) 的任何视图
- 随着 TS 的过渡交错值(从 0.0 - 1.0)
- 动画时长为duration
- 观看动画时长DS = duration * (1 -TS)
- 调用交错分数 SFi = (S(Vi) - S(V0)) / (S(Vn) - S(V0))
- 视图开始动画:(duration-DS) * SFi
这个数学运算可能令人困惑。所以一个实际的例子 如果我有 3 个视图 View1、View2、View3,我将 motionStagger 分别设置为 2、5 和 7,并将动画持续时间设置为 5 秒。 当我将过渡交错设置为 0.4 时,进度如下:
The animation duration is 3.0 sec = 5 * (1- 0.4)
View1 stagger fraction = 0 = (2-2)/(7-2)
View1 starts at 0.0 sec
View1 end at 3.0 sec (0.0 + 3.0)
View2 stagger fraction = 0.6 = (5-2)/(7-2)
View2 starts at 1.2 sec (5.0-3.0) * 0.6
View2 ends at 4.2 sec 1.2 + 3.0
View3 stagger fraction = 1
View3 starts at 2.0 sec (5.0 - 3.0) * 1
View3 ends at 5.0 sec
好的,所以在弄乱了很长时间,反复试验,研究了 this 发布更新中给出的方程式之后,这就是我想出的。
上面的链接文章给了我们一些令人困惑的方程式
Let
The motionStagger value is S(Vi)
The overall stagger value is stagger (from 0.0 - 1.0)
The duration of the animation is duration
The views animation duration = duration * (1 - stagger)
The view starts animating at duration * (stagger - stagger * (S(Vi) - S(V0)) / (S(Vn) - S(V0)))
确定过渡交错值:
要确定您希望整体错开的程度,请考虑您尝试错开的观看次数。
我上面链接的文章指出 viewDuration = totalDuration*(1 - stagger)
所以我们可以重新排列这个等式成为 stagger = 1 - (viewDuration / totalDuration)
。在我的例子中,因为我希望在视图进入时有三个不同的时刻,所以我希望我的 viewDuration / totalDuration
大约是 1/3
。为了简化数学运算,我选择将我的交错设置为 0.6
,使每个 viewDuration 为 400。所以我的转换代码如下所示
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@+id/start"
motion:duration="1000"
motion:motionInterpolator="easeInOut"
motion:staggered="0.6" />
你会注意到我将持续时间增加到 1000 以更清楚地看到交错(一旦你计算出你的交错值,这里的持续时间可以更新并且交错应该适当地缩放以适应时间范围) .
确定个人观点交错值:
所以现在我们需要弄清楚将什么作为 ?在 <Motion motion:motionStagger="?" />
这是数学变得非常复杂的地方。对于我们要设置交错的每个视图,它们应该按交错值排序。我们得到的等式(修改后比文章更具可读性)是:
animationStartTime = totalDuration * (stagger - stagger * ((staggerCurrentView - lowestStaggerValue)/(highestStaggerValue - lowestStaggerValue))
这确实有点复杂,但我可以用我的例子来分解它。
所以对于我的示例,我们已经讨论了我如何让三个视图稍微均匀地交错(这就是为什么我们选择 0.6 的交错值)。根据下面等式的逆结构,我知道具有最高 motionStagger
值的视图将首先进行动画处理。
假设我们有三个视图,一个我想排在第一位的 ImageView,一个我想排在第二位的 TextView,以及一个我想排在第三位的 Button。所以我将给 ImageView 分配一个 motionStagger 值 3,为 TextView 分配一个 motionStagger 值 2,为 TextView 分配一个 motionStagger 值 1。让我们在这里进行计算:
Stagger value = 0.6
motionStaggerValues = 3 (for ImageView), 2 (for TextView), and 1(for Button)
ImageView animationStartTime = 1000 * (0.6 - 0.6 * ((3-1)/(3-1)))
= 1000 * (0.6 - 0.6 * (1)) = 1000 * 0 = 0
所以ImageView从0开始动画,动画持续400ms(如上一节所示)。 现在让我们计算 TextView
Stagger value = 0.6
motionStaggerValues = 3 (for ImageView), 2 (for TextView), and 1(for Button)
TextView animationStartTime = 1000 * (0.6 - 0.6 * ((2-1)/(3-1)))
= 1000 * (0.6 - 0.6 * (1/2)) = 1000 * 0.3 = 300
所以 TextView 在 300 开始动画并持续 400 毫秒。
最后,让我们计算一下按钮的开始时间:
Stagger value = 0.6
motionStaggerValues = 3 (for ImageView), 2 (for TextView), and 1(for Button)
TextView animationStartTime = 1000 * (0.6 - 0.6 * ((1-1)/(3-1)))
= 1000 * (0.6 - 0.6 * (0)) = 1000 * 0.6 = 600
所以按钮从 600 开始动画并持续 400 毫秒。
这些值可以根据您选择的 motionStagger 值进行移动和交错。为了解释起见,我试图让它尽可能简单,但它可能会变得非常复杂,具体取决于您要完成的任务。这是我上面概述的示例的最终代码的样子。
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@id/imageView">
...
<Motion motion:motionStagger="3" />
</Constraint>
<Constraint android:id="@id/textView">
...
<Motion motion:motionStagger="2" />
</Constraint>
<Constraint android:id="@id/button">
...
<Motion motion:motionStagger="1" />
</Constraint>
</ConstraintSet>
您将需要另一个并行 ConstraintSet
作为结束状态。