在之前的文章Android 一种点赞动画的完成中,经过Animation
和Animator
完成了一种点赞动画作用,有知友评论用MotionLayout
是否会比较简单。我之前还没有运用过MotionLayout
,刚好经过完成这个点赞动画来学习一下MotionLayout
的运用。
MotionLayout
MotionLayout
是ConstraintLayout
的子类,包含在ConstraintLayout
库中,在ConstraintLayout
的基础上,增加了管理控件动画的功用。
官方文档
增加库
假如之前没有运用ConstraintLayout
,那么需求在app module下的build.gradle中增加代码,如下:
dependencies {
// 项目中运用AndroidX
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta1'
// 项目中未运用AndroidX
implementation 'com.android.support.constraint:constraint-layout:2.0.0-beta1'
}
点赞作用的完成
尝试运用MotionLayout
来完成之前的点赞动画,最终完成了缩放以及发散作用。
布局中增加MotionLayout
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<!--根节点改为运用MotionLayout-->
<!--layoutDescription 装备MotionScene装备文件-->
<!--showPaths设置是否显示动画的轨迹-->
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
motion:layoutDescription="@xml/example_motion_scene"
tools:showPaths="true">
<include
android:id="@+id/include_title"
layout="@layout/layout_title" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_thumb_up"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
android:src="@drawable/icon_thumb_up"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_thumb_up1"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
android:src="@drawable/icon_thumb_up"
android:visibility="gone"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_thumb_up2"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
android:src="@drawable/icon_thumb_up"
android:visibility="gone"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_thumb_up3"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
android:src="@drawable/icon_thumb_up"
android:visibility="gone"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_thumb_up4"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
android:src="@drawable/icon_thumb_up"
android:visibility="gone"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_thumb_up5"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
android:src="@drawable/icon_thumb_up"
android:visibility="gone"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.motion.widget.MotionLayout>
</layout>
创立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">
<!--装备动画的特点-->
<!--duration 装备动画的持续时间-->
<!--constraintSetStart 装备动画开端时,控件集的状况-->
<!--constraintSetEnd 装备动画完毕时,控件集的状况-->
<!--motionInterpolator 装备动画的插值器,-->
<Transition
android:id="@+id/transition_thumb"
android:duration="1500"
motion:constraintSetEnd="@id/thumb_end"
motion:constraintSetStart="@id/thumb_start"
motion:motionInterpolator="linear">
<!--点击时触发动画-->
<!--targetId 装备触发事情的控件id-->
<!--clickAction 装备点击触发的作用-->
<!--clickAction toggle 当前控件集为开端状况,则播映动画切换至完毕状况,反之亦然-->
<!--clickAction transitionToEnd 播映控件集开端到完毕的动画-->
<!--clickAction transitionToStart 播映控件集完毕到开端的动画-->
<!--clickAction jumpToEnd 不播映动画,控件集直接切换至完毕状况-->
<!--clickAction jumpToStart 不播映动画,控件集直接切换至开端状况-->
<OnClick
motion:clickAction="transitionToEnd"
motion:targetId="@id/iv_thumb_up" />
<!--关键帧集合,用于完成缩放作用-->
<KeyFrameSet>
<!--修改特点-->
<!--framePosition 取值范围为0-100-->
<!--motionTarget 设置修改的对象-->
<!--scaleX 设置x轴缩放巨细-->
<!--scaleY 设置y轴缩放巨细-->
<KeyAttribute
android:scaleX="1.6"
android:scaleY="1.6"
motion:framePosition="25"
motion:motionTarget="@id/iv_thumb_up" />
<KeyAttribute
android:scaleX="1"
android:scaleY="1"
motion:framePosition="50"
motion:motionTarget="@id/iv_thumb_up" />
</KeyFrameSet>
</Transition>
<!--控件集 动画开端时的状况-->
<ConstraintSet android:id="@+id/thumb_start">
<!--与layout文件中的控件对应-->
<!--visibilityMode 假如需求改动控件的可见性,需求将此字段装备为ignore-->
<Constraint
android:id="@+id/iv_thumb_up"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:visibilityMode="ignore" />
<Constraint
android:id="@+id/iv_thumb_up1"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:visibilityMode="ignore">
<!--改动控件的特点-->
<!--attributeName 特点名-->
<!--customFloatValue Float类型特点值-->
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1" />
</Constraint>
<Constraint
android:id="@+id/iv_thumb_up2"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:visibilityMode="ignore">
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1" />
</Constraint>
<Constraint
android:id="@+id/iv_thumb_up3"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:visibilityMode="ignore">
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1" />
</Constraint>
<Constraint
android:id="@+id/iv_thumb_up4"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:visibilityMode="ignore">
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1" />
</Constraint>
<Constraint
android:id="@+id/iv_thumb_up5"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:visibilityMode="ignore">
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="1" />
</Constraint>
</ConstraintSet>
<!--控件集 动画完毕时的状况-->
<ConstraintSet android:id="@+id/thumb_end">
<Constraint
android:id="@+id/iv_thumb_up"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="2dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:visibilityMode="ignore" />
<Constraint
android:id="@+id/iv_thumb_up1"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginTop="110dp"
android:layout_marginEnd="90dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:visibilityMode="ignore">
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0.5" />
</Constraint>
<Constraint
android:id="@+id/iv_thumb_up2"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginStart="70dp"
android:layout_marginTop="95dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:visibilityMode="ignore">
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0.4" />
</Constraint>
<Constraint
android:id="@+id/iv_thumb_up3"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginEnd="85dp"
android:layout_marginBottom="140dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:visibilityMode="ignore">
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0.6" />
</Constraint>
<Constraint
android:id="@+id/iv_thumb_up4"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginStart="60dp"
android:layout_marginBottom="120dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:visibilityMode="ignore">
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0.2" />
</Constraint>
<Constraint
android:id="@+id/iv_thumb_up5"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="60dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:visibilityMode="ignore">
<CustomAttribute
motion:attributeName="alpha"
motion:customFloatValue="0" />
</Constraint>
</ConstraintSet>
</MotionScene>
监听动画状况
class MotionLayoutExampleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: LayoutMotionLayoutExampleActivityBinding = DataBindingUtil.setContentView(this, R.layout.layout_motion_layout_example_activity)
binding.motionLayout.setTransitionListener(object : MotionLayout.TransitionListener {
override fun onTransitionStarted(motionLayout: MotionLayout?, startId: Int, endId: Int) {
// 动画开端
// 把发散的按钮显示出来
binding.ivThumbUp1.visibility = View.VISIBLE
binding.ivThumbUp2.visibility = View.VISIBLE
binding.ivThumbUp3.visibility = View.VISIBLE
binding.ivThumbUp4.visibility = View.VISIBLE
binding.ivThumbUp5.visibility = View.VISIBLE
}
override fun onTransitionChange(motionLayout: MotionLayout?, startId: Int, endId: Int, progress: Float) {
// 动画进行中
}
override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) {
// 动画完成
// 隐藏发散的按钮,将状况还原
binding.root.postDelayed({
binding.ivThumbUp1.visibility = View.GONE
binding.ivThumbUp2.visibility = View.GONE
binding.ivThumbUp3.visibility = View.GONE
binding.ivThumbUp4.visibility = View.GONE
binding.ivThumbUp5.visibility = View.GONE
binding.motionLayout.progress = 0f
}, 200)
}
override fun onTransitionTrigger(motionLayout: MotionLayout?, triggerId: Int, positive: Boolean, progress: Float) {
}
})
}
}
示例
已整合到demo中。
ExampleDemo github
ExampleDemo gitee
作用如图:
大致还原了之前的动画作用,MotionLayout
完成起来确实不杂乱,可是目前还没有找到如何设置动画开端前的延时,因此点击完之后按钮的缩放作用与发散作用之间的距离、发散出去的按钮之间的距离无法彻底恢复。