在本文中,我们将通过各种示例继续介绍MotionLayout的基本功能,介绍自定义属性插值,图像操作和关键帧。
- 示例03:引入自定义属性
- 例04:使用ImageFilterView(1/2):交叉淡入淡出
- 例05:使用ImageFilterView(2/2):饱和度
- 关键帧
- 例06:关键帧(1/2):位置
- 示例07:关键帧(2/2):属性
- 结论
示例03:自定义属性
在第一部分中,我们最后创建了一个自包含的MotionLayout MotionScene。我们可以利用这一点来指定那些属性的过渡不是仅涉及位置。
实际上,最初ConstraintSet只封装了布局规则; 但是对于更丰富的动画,我们经常需要转换其他内容(例如,背景颜色)。在ConstraintLayout 2.0中,ConstraintSet还可以存储自定义属性状态。假设我们想要以下动作,我们视图的背景会改变颜色:
以前,您必须在代码中处理此问题。现在,您可以直接在XML中指定属性:
<Constraint
android:id =“@ + id / button”...>
< CustomAttribute
motion:attributeName =“backgroundColor”
motion:customColorValue =“#D81B60”/>
</ Constraint>
这是上面动画的修改后的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">
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@+id/start"
motion:duration="1000"
motion:interpolator="linear">
<OnSwipe
motion:dragDirection="dragRight"
motion:touchAnchorId="@+id/button"
motion:touchAnchorSide="right" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/button"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#D81B60" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/button"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginEnd="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#9999FF" />
</Constraint>
</ConstraintSet>
</MotionScene>
scene_03.xml
CustomAttribute使用attributeName指定,该属性需要匹配对象的getter /
setter方法,以便:
- getter ? getName例如getBackgroundColor)
- setter ? setName例如setBackgroundColor)
还需要指定值类型:
- customColorValue
- customIntegerValue
- customFloatValue
- customStringValue
- customDimension
- customBoolean
最后,在定义自定义属性时,您需要在开始和结束ConstraintSet中定义它。
示例04:ImageFilterView(1/2)
在处理复杂的过渡时,通常需要对图像进行一些操作,并对它们进行动画处理。ConstraintLayout 2.0带来了一个名为ImageFilterView的小实用程序类(它是AppCompatImageView的子类),可以轻松实现这一点。
让我们举两个图像之间的简单交叉淡入淡出,例如:
我们首先需要使用图像创建一个MotionLayout文件:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.motion.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"
app:layoutDescription="@xml/scene_04"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.constraint.utils.ImageFilterView
android:id="@+id/image"
android:background="@color/colorAccent"
android:src="@drawable/roard"
app:altSrc="@drawable/hoford"
android:layout_width="64dp"
android:layout_height="64dp"/>
</android.support.constraint.motion.MotionLayout>
motion_04_imagefilter.xml
与普通ImageView的主要区别在于altSrc属性:
<android.support.constraint.image.ImageFilterView
android:id="@+id/image"
...
android:src="@drawable/roard"
app:altSrc="@drawable/hoford"/>
MotionScene文件将仅在crossfade属性上应用自定义属性:
<?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"
motion:interpolator="linear">
<OnSwipe
motion:dragDirection="dragRight"
motion:touchAnchorId="@+id/image"
motion:touchAnchorSide="right" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginStart="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="crossfade"
motion:customFloatValue="0" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginEnd="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="crossfade"
motion:customFloatValue="1" />
</Constraint>
</ConstraintSet>
</MotionScene>
scene_04.xml
示例05:ImageFilterView(2/2)
- 饱和度:0 =灰度,1 =原始,2 =超饱和
- 对比度:1 =不变,0 =灰色,2 =高对比度
- 温暖:1 =中性,2 =温暖(红色),0.5 =冷(蓝色)
- 交叉淡化(带app:altSrc)
这是另一个展示如何使用图像饱和度的示例:
这个csdn不知道
只需使用自定义属性即可指定饱和度:
<CustomAttribute
motion:attributeName="saturation"
motion:customFloatValue="1" />
这是我们在这个例子中使用的MotionLayout文件:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.motion.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/motionLayout"
app:layoutDescription="@xml/scene_05"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.constraint.utils.ImageFilterView
android:id="@+id/image"
android:src="@drawable/sunset2"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="300dp" />
</android.support.constraint.motion.MotionLayout>
motion_05_imagefilter.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">
<Transition
motion:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000">
<OnSwipe
motion:touchAnchorId="@+id/image"
motion:touchAnchorSide="top"
motion:dragDirection="dragUp" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="300dp"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="saturation"
motion:customFloatValue="1" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="300dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent">
<CustomAttribute
motion:attributeName="saturation"
motion:customFloatValue="0" />
</Constraint>
</ConstraintSet>
</MotionScene>
关键帧
MotionLayout的一般思想是“ 静止状态 ”实现为ConstraintSets。这样,我们就知道生成的布局将正确地适应不同的屏幕尺寸:实质上,MotionLayout的行为就像典型的ConstraintLayout。
在某些情况下,您可能希望拥有一个中间状态 - 要经历的状态,而不是要留下的状态。您可以指定两个以上的ConstraintSets,但更轻量级的方法是使用关键帧。
关键帧可以应用于位置或属性值; 它们基本上允许您指定转换期间某个时间点的更改。
例如,您可能希望在转换的25%处,窗口小部件应该变为红色。或者在转换的50%时,小部件应该向上移动。
例06:关键帧,位置
有几种方法(pathRelative,deltaRelative,parentRelative)你可以设置一个位置关键帧(KeyPosition),我们将在详细覆盖第四部分本系列。
作为位置关键帧的快速介绍,以下是如何指定在总转换的50%处发生的中间位置,位于屏幕的25%:
<Transition ...>
<KeyFrameSet>
<KeyPosition
motion:keyPositionType="parentRelative"
motion:percentY="0.25"
motion:framePosition="50"
motion:target="@+id/button"/>
</KeyFrameSet>
</Transition>
由此产生的移动将是:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.motion.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"
app:layoutDescription="@xml/scene_06"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="@+id/button"
android:background="@color/colorAccent"
android:layout_width="64dp"
android:layout_height="64dp" />
</android.support.constraint.motion.MotionLayout>
scene_06.xml
MotionScene文件与我们之前看到的文件非常相似,只增加了一个KeyPosition元素:
<?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:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000"
motion:interpolator="linear">
<OnSwipe
motion:touchAnchorId="@+id/button"
motion:touchAnchorSide="right"
motion:dragDirection="dragRight" />
<KeyFrameSet>
<KeyPosition
motion:keyPositionType="parentRelative"
motion:percentY="0.25"
motion:framePosition="50"
motion:target="@+id/button"/>
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/button"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#D81B60"/>
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/button"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginEnd="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#9999FF"/>
</Constraint>
</ConstraintSet>
</MotionScene>
示例07:关键帧,属性
以与定位关键帧类似的方式,您可以在转换中的特定点指定属性值(使用KeyAttribute)。
例如,我们可能希望指定我们在相同的50%位置操作的对象的比例和旋转,以获得以下转换:
这可以通过在以下内容中添加KeyAttribute元素来实现KeyFrameSet:
<KeyFrameSet>
<KeyAttribute
android:scaleX="2"
android:scaleY="2"
android:rotation="-45"
motion:framePosition="50"
motion:target="@id/button" />
</KeyFrameSet>
该MotionLayout文件与上一个示例中的MotionScene文件相同,文件的唯一区别是添加KeyAttribute:
<?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:constraintSetStart="@+id/start"
motion:constraintSetEnd="@+id/end"
motion:duration="1000"
motion:interpolator="linear">
<OnSwipe
motion:touchAnchorId="@+id/button"
motion:touchAnchorSide="right"
motion:dragDirection="dragRight" />
<KeyFrameSet>
<KeyAttribute
android:scaleX="2"
android:scaleY="2"
android:rotation="-45"
motion:framePosition="50"
motion:target="@id/button" />
<KeyPosition
motion:keyPositionType="screenRelative"
motion:percentY="0.2"
motion:framePosition="50"
motion:target="@id/button"/>
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/button"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#D81B60"/>
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/button"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginEnd="8dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent">
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#9999FF"/>
</Constraint>
</ConstraintSet>
</MotionScene>
结论
第二篇文章介绍了MotionLayout的更高级功能,给出了如何利用自定义属性和关键帧创建更具吸引力的动画的示例。