一、过渡动画
以下面的布局为例,让上面的球变大二倍
布局文件如下
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play_basketball"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play_basketball"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv_one" />
</androidx.constraintlayout.widget.ConstraintLayout>
布局效果
1、属性动画
binding.ivOne.setOnClickListener {
with(binding.ivOne.animate()){
scaleX(2f)
scaleY(2f)
duration = 800
start()
}
}
效果展示
2、TransitionManager.beginDelayedTransition
binding.ivOne.setOnClickListener {
val width = binding.ivOne.width
//设置过渡动画(底层也是属性动画,关注captureStartValues和captureEndValues方法)
TransitionManager.beginDelayedTransition(binding.root)
val constraintSet = ConstraintSet()
constraintSet.clone(binding.root)
//修改ImageView的右边为父控件的右边,如果想修改多个属性需要写多条constraintSet.connect()
//constraintSet.connect(
// binding.ivOne.id, ConstraintSet.END, binding.root.id, ConstraintSet.END
//)
constraintSet.constrainWidth(binding.ivOne.id, width * 2)
constraintSet.constrainHeight(binding.ivOne.id, width * 2)
constraintSet.applyTo(binding.root)
}
效果展示
这个方式的优点是可以改变控件的属性并重新排布。
3、TransitionManager.go
通过设置开始布局和结束布局实现动画。
Activity的布局代码:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="@layout/go_start" />
</androidx.constraintlayout.widget.ConstraintLayout>
go_start.xml的代码:
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv"
android:layout_width="150dp"
android:layout_height="0dp"
android:src="@mipmap/ig_guimie"
app:layout_constraintDimensionRatio="0.685"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="@string/text_one"
android:textColor="@color/black"
android:textSize="26sp"
app:layout_constraintLeft_toRightOf="@id/iv"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/text_two"
android:textColor="#666666"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv" />
</merge>
go_end.xml的代码:
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/ig_guimie"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="@string/text_one"
android:textColor="@color/black"
android:textSize="26sp"
app:layout_constraintLeft_toRightOf="@id/iv"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/text_two"
android:textColor="#666666"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv" />
</merge>
注意go_start.xml和go_end.xml的布局ID必须一致。
Activity中的代码:
class MainActivity : AppCompatActivity(), View.OnClickListener {
var toggle = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bindData()
}
override fun onClick(v: View?) {
val root = findViewById<ConstraintLayout>(R.id.root)
val startScene = Scene.getSceneForLayout(root, R.layout.go_start, this)
val endScene = Scene.getSceneForLayout(root, R.layout.go_end, this)
if (!toggle) {
TransitionManager.go(endScene,ChangeBounds())
} else {
TransitionManager.go(startScene,ChangeBounds())
}
//重新绑定数据
bindData()
toggle = !toggle
}
private fun bindData() {
findViewById<ImageView>(R.id.iv).setOnClickListener(this)
findViewById<TextView>(R.id.tv_one).text = getString(R.string.text_one)
findViewById<TextView>(R.id.tv_two).text = getString(R.string.text_two)
}
}
效果展示:
TransitionManager.go方法第二个参数就是动画效果,主要包括以下这些:
继承Transiton类的效果
ChangeBounds:检测view的位置边界创建移动和缩放动画
ChangeTransform:检测view的scale和rotation创建缩放和旋转动画
ChangeClipBounds:检测view的剪切区域的位置边界,和ChangeBounds类似。不过ChangeBounds针对的是view而ChangeClipBounds针对的是view的剪切区域(setClipBound(Rect rect) 中的rect)。如果没有设置则没有动画效果
ChangeImageTransform:检测ImageView的尺寸,位置以及ScaleType,并创建相应动画。
Fade,Slide,Explode:根据view的visibility的状态执行渐入渐出,滑动,分解动画。
注意,基于基类封装的ViewBinding获取的ID不起作用,原因是Scene类中方法getSceneRoot().removeAllViews把View都移除掉了,需要重新获取ID
4、使用ConstraintSet优化代码
那么有没有其他方式可以优化上面的代码呢? 是有的,不需要重新绑定数据(bindData),代码如下:
go_start.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root" //根布局添加ID
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv"
android:layout_width="150dp"
android:layout_height="0dp"
android:src="@mipmap/ig_guimie"
app:layout_constraintDimensionRatio="0.685"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="@string/text_one"
android:textColor="@color/black"
android:textSize="26sp"
app:layout_constraintLeft_toRightOf="@id/iv"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/text_two"
android:textColor="#666666"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv" />
</androidx.constraintlayout.widget.ConstraintLayout>
go_end.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root" //根布局添加ID
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/ig_guimie"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="@string/text_one"
android:textColor="@color/black"
android:textSize="26sp"
app:layout_constraintLeft_toRightOf="@id/iv"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/text_two"
android:textColor="#666666"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv" />
</androidx.constraintlayout.widget.ConstraintLayout>
Activity的代码
class MainActivity : AppCompatActivity(), View.OnClickListener {
var toggle = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.go_start)
findViewById<ImageView>(R.id.iv).setOnClickListener(this)
}
override fun onClick(v: View?) {
val root = findViewById<ConstraintLayout>(R.id.root)
TransitionManager.beginDelayedTransition(root)
val constraintSet = ConstraintSet()
if (!toggle) {
constraintSet.clone(this,R.layout.go_end)
} else {
constraintSet.clone(this,R.layout.go_start)
}
constraintSet.applyTo(root)
toggle = !toggle
}
}
效果同上,避免每次重新绑定数据
二、MotionLayout
1、使用MotionLayout进一步优化上面的代码
使用MotionLayout只需要写一个布局文件,但是需要增加一个描述控件属性变化的xml文件。
activity_main.xml的代码
<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/motion"> //引入motion文件(必须)
<ImageView //变化的只有ImageView,下面二个控件不用管
android:id="@+id/iv"
android:layout_width="150dp"
android:layout_height="0dp"
android:src="@mipmap/ig_guimie"
app:layout_constraintDimensionRatio="0.685"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="@string/text_one"
android:textColor="@color/black"
android:textSize="26sp"
app:layout_constraintLeft_toRightOf="@id/iv"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/text_two"
android:textColor="#666666"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv" />
</androidx.constraintlayout.motion.widget.MotionLayout>
motion.xml的代码
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
<Transition
//指定开始和结束的ID
app:constraintSetEnd="@id/end"
app:constraintSetStart="@id/start">
<!--点击事件,当前版本点击事件和触摸事件的控件ID不能相同,如果相同则二个事件只能二选一-->
<OnClick
app:clickAction="toggle" //toggle切换,此外还有jumpToStart/End,transitionToStart/End
app:targetId="@+id/iv" />
<!--触摸事件,当前版本点击事件和触摸事件的控件ID不能相同,如果相同则二个事件只能二选一-->
<!--<OnSwipe
app:touchRegionId="@+id/iv"
app:dragDirection="dragDown" //拖拽的方向:dragDown/End/Left/Right/Start/Up
app:onTouchUp="autoComplete" //手指抬起时: autoComplete/autoCompleteToStart/autoCompleteToEnd/Stop等等
/>-->
</Transition>
//设置开始的ConstraintSet
<ConstraintSet android:id="@+id/start"></ConstraintSet>
//设置结束的ConstraintSet,里面包裹的就是变化后的Imageview,但必须把节点修改为Constraint,如果有多个变化的控件都要这样改
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/ig_guimie"
app:layout_constraintDimensionRatio="0.685"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
</MotionScene>
MainActivity中不需要写任何控制代码。
class MainActivity : BaseBindingActivity<ActivityMainBinding>(){
}
效果同上,不需要写二个布局文件,且不影响ViewBinding的封装。但是写到motion.xml的控件(有定义OnClick)会不再响应Activity写的点击事件。
延伸:如果将点击事件改触摸事件,会随着手指移动完成动画,也可以快速滑动,MotionLayout会根据滑动的距离自动判断回到起点还是完成动画。修改onTouchUp参数会有不同的效果。
2、MotionLayout特性介绍
注意:MotionLayout是继承自ConstraintLayout,MotionLayout的子控件必须有ID,不然会报下面的错误:
java.lang.RuntimeException: All children of ConstraintLayout must have ids to use ConstraintSet
布局代码如下:
<?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"
app:layoutDescription="@xml/motion"
app:showPaths="true" //查看路径的属性设置为true
tools:context=".MainActivity">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/iv" //子控件必须有ID
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/girl"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.motion.widget.MotionLayout>
motion.xml代码如下,很简单,后面再一点点加:
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetStart="@id/start"
app:constraintSetEnd="@id/end">
</Transition>
<ConstraintSet android:id="@+id/start">
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
</ConstraintSet>
</MotionScene>
效果展示:
1)添加结束布局,让图片从左上角移动到右下角
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="@id/end"
app:constraintSetStart="@id/start"
app:duration="1000" //动画执行的时间
app:motionInterpolator="@string/fab_transformation_scrim_behavior"> //添加插值器
<OnClick
app:clickAction="toggle"
app:targetId="@+id/iv" />
</Transition>
<ConstraintSet android:id="@+id/start"> //Set是一个集合,可以定义多个Constraint
<Constraint android:id="@+id/iv"></Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end"> //Set是一个集合,可以定义多个Constraint
<Constraint android:id="@+id/iv">
<Layout //修改结束的布局属性
android:id="@+id/iv"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/girl"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<CustomAttribute //添加布局中没有的属性,但这个属性必须控件有,而且这个属性设置后不可逆(见效果),如果希望属性可逆,在开始节点设置回来就可以了
app:attributeName="saturation" //设置饱和度
app:customFloatValue="0.5" />
<PropertySet android:alpha="0.5" /> //透明度,Visibility的三个属性也在这里,这里设置的属性可逆
</Constraint>
</ConstraintSet>
</MotionScene>
效果展示
2)修改运动轨迹
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="@id/end"
app:constraintSetStart="@id/start">
<OnClick
app:clickAction="toggle"
app:targetId="@+id/iv" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/iv">
<Motion //开始时定义Motion节点
app:pathMotionArc="startHorizontal" //开始时先水平
app:transitionEasing="accelerate" /> //accelerate:加速/decelerate:减速
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/iv">
<Layout
android:id="@+id/iv"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/girl"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</Constraint>
</ConstraintSet>
</MotionScene>
效果展示
3)增加旋转缩放效果
在ConstraintSet的end节点增加这些效果,使动画结束时实现
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="@id/end"
app:constraintSetStart="@id/start"
app:duration="1500">
<OnClick
app:clickAction="toggle"
app:targetId="@+id/iv" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/iv">
<Motion app:pathMotionArc="startHorizontal" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/iv">
<Layout
android:id="@+id/iv"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/girl"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<!--结束节点增加常规动画,旋转180度,放大2倍-->
<Transform
android:rotation="180"
android:scaleX="2.0"
android:scaleY="2.0" />
</Constraint>
</ConstraintSet>
</MotionScene>
效果展示
4)属性关键帧
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="@id/end"
app:constraintSetStart="@id/start"
app:duration="1500">
<OnClick
app:clickAction="toggle"
app:targetId="@+id/iv" />
<!--关键帧-->
<KeyFrameSet>
<!--属性关键帧-->
<KeyAttribute
android:rotation="360" //旋转360度
android:scaleX="2.0" //放大2倍
android:scaleY="2.0"
app:framePosition="50" //关键帧的位置,动画执行到50%的时候
app:motionTarget="@id/iv" /> //作用的对象的ID
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/iv">
<Motion app:pathMotionArc="startHorizontal" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/iv">
<Layout
android:id="@+id/iv"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/girl"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</Constraint>
</ConstraintSet>
</MotionScene>
在关键帧时实现效果,动画结束时实现结束节点的效果。效果展示
5)位置关键帧
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="@id/end"
app:constraintSetStart="@id/start"
app:duration="1500">
<OnClick
app:clickAction="toggle"
app:targetId="@+id/iv" />
<!--关键帧-->
<KeyFrameSet>
<!--位置关键帧-->
<KeyPosition
app:motionTarget="@id/iv" //作用的对象的ID
app:framePosition="50" //关键帧的位置,动画执行到50%的时候
app:pathMotionArc="startVertical" //如果开始节点不设置pathMotionArc,这里设置无效
app:keyPositionType="pathRelative" //有三种,最常用的是二种parentRelative和deltaRelative,
这里是以pathRelative举例说明坐标系。parentRelative是以父容器为基准设置坐标系,deltaRelative是
以MotionLayout为基准设置坐标系,而pathRelative则是以路径方向定义X轴,相应定义Y轴
app:percentX="0.90" //X坐标的位置
app:percentY="0.25" /> //Y坐标的位置
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/iv">
<Motion app:pathMotionArc="startHorizontal" /> //这里设置pathMotionArc,上面的pathMotionArc才会生效
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/iv">
<Layout
android:id="@+id/iv"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/girl"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</Constraint>
</ConstraintSet>
</MotionScene>
效果展示
坐标系
6)循环关键帧
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="@id/end"
app:constraintSetStart="@id/start"
app:duration="1500">
<OnClick
app:clickAction="toggle"
app:targetId="@+id/iv" />
<!--关键帧-->
<KeyFrameSet>
<!--循环关键帧-->
<KeyCycle
android:rotation="0"
app:framePosition="0" //动画完成度0%
app:motionTarget="@id/iv"
app:wavePeriod="0"
app:waveShape="sin" />
<KeyCycle
android:rotation="90" //旋转90度
app:framePosition="50" //动画完成度50%
app:motionTarget="@id/iv"
app:wavePeriod="2" //循环次数
app:waveShape="sin" /> //循环参数(见下方)
<KeyCycle
android:rotation="0"
app:framePosition="100" //动画完成度100%
app:motionTarget="@id/iv"
app:wavePeriod="0"
app:waveShape="sin" />
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/iv">
<Layout
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/girl"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent" />
<Motion app:pathMotionArc="startHorizontal" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/iv">
<Layout
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/girl"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</Constraint>
</ConstraintSet>
</MotionScene>
参数说明
waveShape参数有以下几种,具体效果可自行尝试
<attr format="enum|string" name="waveShape">
<enum name="sin" value="0"/> //按三角函数的计算结果
<enum name="square" value="1"/> //方形翻转
<enum name="triangle" value="2"/> //三角形
<enum name="sawtooth" value="3"/> //锯齿,有停顿
<enum name="reverseSawtooth" value="4"/> //与sawtooth方向相反
<enum name="cos" value="5"/> //按三角函数的计算结果
<enum name="bounce" value="6"/> //有阻尼的反弹
</attr>
效果展示
7)时间关键帧
改成触摸事件更能看出随时间的变化
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="@id/end"
app:constraintSetStart="@id/start"
app:duration="1500">
<!--改成触摸事件-->
<OnSwipe
app:dragDirection="dragDown"
app:onTouchUp="autoComplete"
app:touchRegionId="@+id/iv" />
<!--关键帧-->
<KeyFrameSet>
<!--时间关键帧-->
<KeyTimeCycle
android:rotation="0"
app:framePosition="0"
app:motionTarget="@id/iv"
app:wavePeriod="0"
app:waveShape="sin" />
<KeyTimeCycle
android:rotation="90"
app:framePosition="50"
app:motionTarget="@id/iv"
app:wavePeriod="2" //每秒循环的次数
app:waveShape="sin" />
<KeyTimeCycle
android:rotation="0"
app:framePosition="100"
app:motionTarget="@id/iv"
app:wavePeriod="0"
app:waveShape="sin" />
</KeyFrameSet>
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/iv">
<Motion app:pathMotionArc="startHorizontal" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/iv">
<Layout
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/girl"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</Constraint>
</ConstraintSet>
</MotionScene>
触摸,中途不抬起的效果展示
8)AS对MotionLayout的支持
点击start可以看到开始,点击end可以看到结束
点击中间的线可以看到关键帧,点击播放按钮可以播放
--个人学习笔记