Android开发教程案例源码分享-匹配动画多个头像飘动效果
Android开发教程案例源码分享-匹配动画多个头像飘动效果
匹配往往出现多个头像飘动,吸引人点击,有时出现的位置还不固定
一、思路:
用MotionLayout
二、效果图:
看视频更直观点:
Android开发教程案例源码分享-匹配动画多个头像飘动效果
三、关键代码:
xml布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/color_1F1C4C">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_img_anim"
android:layout_width="@dimen/dp_240"
android:layout_height="@dimen/dp_240"
android:layout_gravity="center_horizontal"
android:layout_marginTop="@dimen/dp_70"
>
<ImageView
android:id="@+id/iv_video_match"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/img_video_match"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/cl_amin1"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_340"
android:layout_marginTop="@dimen/dp_20"
app:layoutDescription="@xml/activity_video_match_scene1"
>
<ImageView
android:id="@+id/iv_anim1"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:scaleType="centerCrop"
android:src="@mipmap/yishi"
/>
</androidx.constraintlayout.motion.widget.MotionLayout>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/cl_amin2"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_340"
android:layout_marginTop="@dimen/dp_20"
app:layoutDescription="@xml/activity_video_match_scene2"
>
<ImageView
android:id="@+id/iv_anim2"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:src="@mipmap/yishi2"
android:scaleType="centerCrop"
/>
</androidx.constraintlayout.motion.widget.MotionLayout>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/cl_amin3"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_340"
android:layout_marginTop="@dimen/dp_20"
app:layoutDescription="@xml/activity_video_match_scene3"
>
<ImageView
android:id="@+id/iv_anim3"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:src="@mipmap/yishi3"
android:scaleType="centerCrop"
/>
</androidx.constraintlayout.motion.widget.MotionLayout>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/cl_amin4"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_340"
android:layout_marginTop="@dimen/dp_20"
app:layoutDescription="@xml/activity_video_match_scene4"
>
<ImageView
android:id="@+id/iv_anim4"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:src="@mipmap/yishi4"
android:scaleType="centerCrop"
/>
</androidx.constraintlayout.motion.widget.MotionLayout>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/cl_amin5"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_340"
android:layout_marginTop="@dimen/dp_20"
app:layoutDescription="@xml/activity_video_match_scene5"
>
<ImageView
android:id="@+id/iv_anim5"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:src="@mipmap/yishi5"
android:scaleType="centerCrop"
/>
</androidx.constraintlayout.motion.widget.MotionLayout>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/cl_amin6"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_340"
android:layout_marginTop="@dimen/dp_20"
app:layoutDescription="@xml/activity_video_match_scene6"
>
<ImageView
android:id="@+id/iv_anim6"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:src="@mipmap/yishi6"
android:scaleType="centerCrop"
/>
</androidx.constraintlayout.motion.widget.MotionLayout>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/cl_amin7"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_340"
android:layout_marginTop="@dimen/dp_20"
app:layoutDescription="@xml/activity_video_match_scene7"
>
<ImageView
android:id="@+id/iv_anim7"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:src="@mipmap/yishi7"
android:scaleType="centerCrop"
/>
</androidx.constraintlayout.motion.widget.MotionLayout>
</FrameLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
kotlin代码
package com.cong.mymoreheadanim
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.view.View
import androidx.constraintlayout.motion.widget.MotionLayout
import com.cong.mymoreheadanim.databinding.ActivityVideoMatchBinding
import com.zailiaoliao.lib.image.ImageLoader
class MainActivity : AppCompatActivity() {
lateinit var mBinding:ActivityVideoMatchBinding
private var isStart2 = false
private var isStart3 = false
private var isStart4 = false
private var isStart5 = false
private var isStart6 = false
private var isStart7 = false
private var isStartAnim1 = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = ActivityVideoMatchBinding.inflate(layoutInflater)
setContentView(mBinding.root)
ImageLoader.loadAvatar(mBinding.ivAnim1,R.mipmap.yishi)
ImageLoader.loadAvatar(mBinding.ivAnim2,R.mipmap.yishi2)
ImageLoader.loadAvatar(mBinding.ivAnim3,R.mipmap.yishi3)
ImageLoader.loadAvatar(mBinding.ivAnim4,R.mipmap.yishi4)
ImageLoader.loadAvatar(mBinding.ivAnim5,R.mipmap.yishi5)
ImageLoader.loadAvatar(mBinding.ivAnim6,R.mipmap.yishi6)
ImageLoader.loadAvatar(mBinding.ivAnim7,R.mipmap.yishi7)
dealAnimListener()
}
override fun onResume() {
super.onResume()
if (!isStartAnim1){
Handler().postDelayed({
mBinding.clAmin1.transitionToStart()
mBinding.clAmin1.setTransition(R.id.left_to_right)
mBinding.clAmin1.transitionToEnd()
isStartAnim1 = true
},500)
}
}
private fun dealAnimListener(){
mBinding.clAmin1.addTransitionListener(object : MotionLayout.TransitionListener{
override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {
mBinding.ivAnim1.visibility = View.VISIBLE
}
override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) {
if (p3 >= 0.2f && !isStart2){
mBinding.clAmin2.transitionToStart()
mBinding.clAmin2.setTransition(R.id.left_to_right2)
mBinding.clAmin2.transitionToEnd()
isStart2 = true
}
}
override fun onTransitionCompleted(p0: MotionLayout, p1: Int) {
isStart2 = false
}
override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {
}
})
mBinding.clAmin2.addTransitionListener(object : MotionLayout.TransitionListener{
override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {
mBinding.ivAnim2.visibility = View.VISIBLE
}
override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) {
if (p3 >= 0.2f && !isStart3){
mBinding.clAmin3.transitionToStart()
mBinding.clAmin3.setTransition(R.id.left_to_right3)
mBinding.clAmin3.transitionToEnd()
isStart3 = true
}
}
override fun onTransitionCompleted(p0: MotionLayout, p1: Int) {
isStart3 = false
}
override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {
}
})
mBinding.clAmin3.addTransitionListener(object : MotionLayout.TransitionListener{
override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {
mBinding.ivAnim3.visibility = View.VISIBLE
}
override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) {
if (p3 >= 0.5f && !isStart4){
mBinding.clAmin4.transitionToStart()
mBinding.clAmin4.setTransition(R.id.left_to_right4)
mBinding.clAmin4.transitionToEnd()
isStart4 = true
}
}
override fun onTransitionCompleted(p0: MotionLayout, p1: Int) {
isStart4 = false
}
override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {
}
})
mBinding.clAmin4.addTransitionListener(object : MotionLayout.TransitionListener{
override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {
mBinding.ivAnim4.visibility = View.VISIBLE
}
override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) {
if (p3 >= 0.3f && !isStart5){
mBinding.clAmin5.transitionToStart()
mBinding.clAmin5.setTransition(R.id.left_to_right5)
mBinding.clAmin5.transitionToEnd()
isStart5 = true
}
}
override fun onTransitionCompleted(p0: MotionLayout, p1: Int) {
isStart5 = false
}
override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {
}
})
mBinding.clAmin5.addTransitionListener(object : MotionLayout.TransitionListener{
override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {
mBinding.ivAnim5.visibility = View.VISIBLE
}
override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) {
if (p3 >= 0.3f && !isStart6){
mBinding.clAmin6.transitionToStart()
mBinding.clAmin6.setTransition(R.id.left_to_right6)
mBinding.clAmin6.transitionToEnd()
isStart6 = true
}
}
override fun onTransitionCompleted(p0: MotionLayout, p1: Int) {
isStart6 = false
}
override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {
}
})
mBinding.clAmin6.addTransitionListener(object : MotionLayout.TransitionListener{
override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {
mBinding.ivAnim6.visibility = View.VISIBLE
}
override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) {
if (p3 >= 0.3f && !isStart7){
mBinding.clAmin7.transitionToStart()
mBinding.clAmin7.setTransition(R.id.left_to_right7)
mBinding.clAmin7.transitionToEnd()
isStart7 = true
}
}
override fun onTransitionCompleted(p0: MotionLayout, p1: Int) {
isStart7 = false
mBinding.ivAnim1.visibility = View.GONE
mBinding.clAmin1.transitionToStart()
mBinding.clAmin1.setTransition(R.id.left_to_right)
mBinding.clAmin1.transitionToEnd()
}
override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {
}
})
mBinding.clAmin7.addTransitionListener(object : MotionLayout.TransitionListener{
override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {
mBinding.ivAnim7.visibility = View.VISIBLE
}
override fun onTransitionChange(p0: MotionLayout?, p1: Int, p2: Int, p3: Float) {
}
override fun onTransitionCompleted(p0: MotionLayout, p1: Int) {
}
override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {
}
})
}
}
项目demo源码结构图:
有问题或者需要demo源码的私信我