Android实现点赞动画

点击后的缩放效果

本文通过ScaleAnimation 实现缩放效果,代码如下:

private fun playThumbUpScaleAnimator() {
    // x、y轴方向都从1倍放大到2倍,以控件的中心为原点进行缩放
    ScaleAnimation(1f, 2f, 1f, 2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f).run {
        // 先取消控件当前的动画效果(重复点击时)
        view.clearAnimation()
        // 设置动画的持续时间
        duration = 300
        // 开始播放动画
        view.startAnimation(this)
    }
}

拇指的散开效果

有5个拇指分别往不同的方向移动,本文通过动态添加View,并对View设置动画来实现。可以看到在移动的同时还有缩放的效果,所以需要同时播放几个动画。

本文通过ValueAnimatorAnimatorSet来实现该效果,代码如图:

// 此数组控制动画的效果
// 第一个参数控制X轴移动距离
// 第二个参数控制Y轴移动距离
// 第三个参数控制缩放的倍数(基于原大小)
val animatorConfig: ArrayList<ArrayList<Float>> = arrayListOf(
    arrayListOf(-160f, 150f, 1f),
    arrayListOf(80f, 130f, 1.1f),
    arrayListOf(-120f, -170f, 1.3f),
    arrayListOf(80f, -130f, 1f),
    arrayListOf(-20f, -80f, 0.8f))

private fun playDiffusionAnimator() {
    for (index in 0 until 5) {
        binding.root.run {
            if (this is ViewGroup) {
                // 创建控件
                val ivThumbUp = AppCompatImageView(context)
                ivThumbUp.setImageResource(R.drawable.icon_thumb_up)
                // 设置与原控件一样的大小
                ivThumbUp.layoutParams = FrameLayout.LayoutParams(DensityUtil.dp2Px(25), DensityUtil.dp2Px(25))
                // 先设置为全透明
                ivThumbUp.alpha = 0f
                addView(ivThumbUp)
                // 设置与原控件一样的位置
                ivThumbUp.x = binding.ivThumbUp.x
                ivThumbUp.y = binding.ivThumbUp.y
                AnimatorSet().apply {
                    // 设置动画集开始播放前的延迟
                    startDelay = 330L + index * 50L
                    // 设置动画监听
                    addListener(object : Animator.AnimatorListener {
                        override fun onAnimationStart(animation: Animator) {
                            // 开始播放时把控件设置为不透明
                            ivThumbUp.alpha = 1f
                        }

                        override fun onAnimationEnd(animation: Animator) {
                            // 播放结束后再次设置为透明,并从根布局中移除
                            ivThumbUp.alpha = 0f
                            ivThumbUp.clearAnimation()
                            ivThumbUp.post { removeView(ivThumbUp) }
                        }

                        override fun onAnimationCancel(animation: Animator) {}

                        override fun onAnimationRepeat(animation: Animator) {}
                    })
                    // 设置三个动画同时播放
                    playTogether(
                        // 缩放动画
                        ValueAnimator.ofFloat(1f, animatorConfig[index][2]).apply {
                            duration = 700
                            // 设置插值器,速度一开始快,快结束时减慢
                            interpolator = DecelerateInterpolator()
                            addUpdateListener { values ->
                                 (values.animatedValue as Float).let { value ->
                                    ivThumbUp.scaleX = value
                                    ivThumbUp.scaleY = value
                                }
                            }
                        },
                        // X轴的移动动画
                        ValueAnimator.ofFloat(ivThumbUp.x, ivThumbUp.x + animatorConfig[index][0]).apply {
                            duration = 700
                            interpolator = DecelerateInterpolator()
                            addUpdateListener { values ->
                                ivThumbUp.x = values.animatedValue as Float
                            }
                        },
                        // Y轴的移动动画
                        ValueAnimator.ofFloat(ivThumbUp.y, ivThumbUp.y + animatorConfig[index][1]).apply {
                            duration = 700
                            interpolator = DecelerateInterpolator()
                            addUpdateListener { values ->
                                ivThumbUp.y = values.animatedValue as Float
                            }
                        })
                }.start()
            }
        }
    }
}

示例

整合之后做了个示例Demo,完整代码如下:

class AnimatorSetExampleActivity : BaseGestureDetectorActivity() {

    private lateinit var binding: LayoutAnimatorsetExampleActivityBinding

    private val animatorConfig: ArrayList<java.util.ArrayList<Float>> = arrayListOf(
        arrayListOf(-160f, 150f, 1f),
        arrayListOf(80f, 130f, 1.1f),
        arrayListOf(-120f, -170f, 1.3f),
        arrayListOf(80f, -130f, 1f),
        arrayListOf(-20f, -80f, 0.8f))


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.layout_animatorset_example_activity)
        binding.ivThumbUp.setOnClickListener {
            playThumbUpScaleAnimator()
            playDiffusionAnimator()
        }
    }

    private fun playThumbUpScaleAnimator() {
        // x,y轴方向都从1倍放大到2倍,以控件的中心为原点进行缩放
        ScaleAnimation(1f, 2f, 1f, 2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f).run {
            // 先取消控件当前的动画效果(重复点击时)
            binding.ivThumbUp.clearAnimation()
            // 设置动画的持续时间
            duration = 300
            // 开始播放动画
            binding.ivThumbUp.startAnimation(this)
        }
    }

    private fun playDiffusionAnimator() {
        for (index in 0 until 5) {
            binding.root.run {
                if (this is ViewGroup) {
                    // 创建控件
                    val ivThumbUp = AppCompatImageView(context)
                    ivThumbUp.setImageResource(R.drawable.icon_thumb_up)
                    // 设置与原控件一样的大小
                    ivThumbUp.layoutParams = FrameLayout.LayoutParams(DensityUtil.dp2Px(25), DensityUtil.dp2Px(25))
                    // 先设置为全透明
                    ivThumbUp.alpha = 0f
                    addView(ivThumbUp)
                    // 设置与原控件一样的位置
                    ivThumbUp.x = binding.ivThumbUp.x
                    ivThumbUp.y = binding.ivThumbUp.y
                    AnimatorSet().apply {
                        // 设置动画集开始播放前的延迟
                        startDelay = 330L + index * 50L
                        // 设置动画监听
                        addListener(object : Animator.AnimatorListener {
                            override fun onAnimationStart(animation: Animator) {
                                // 开始播放时把控件设置为不透明
                                ivThumbUp.alpha = 1f
                            }

                            override fun onAnimationEnd(animation: Animator) {
                                // 播放结束后再次设置为透明,并从根布局中移除
                                ivThumbUp.alpha = 0f
                                ivThumbUp.clearAnimation()
                                ivThumbUp.post { removeView(ivThumbUp) }
                            }

                            override fun onAnimationCancel(animation: Animator) {}

                            override fun onAnimationRepeat(animation: Animator) {}
                        })
                        // 设置三个动画同时播放
                        playTogether(
                            // 缩放动画
                            ValueAnimator.ofFloat(1f, animatorConfig[index][2]).apply {
                                duration = 700
                                // 设置插值器,速度一开始快,快结束时减缓
                                interpolator = DecelerateInterpolator()
                                addUpdateListener { values ->
                                    (values.animatedValue as Float).let { value ->
                                        ivThumbUp.scaleX = value
                                        ivThumbUp.scaleY = value
                                    }
                                }
                            },
                            // Y轴的移动动画
                            ValueAnimator.ofFloat(ivThumbUp.x, ivThumbUp.x + animatorConfig[index][0]).apply {
                                duration = 700
                                interpolator = DecelerateInterpolator()
                                addUpdateListener { values ->
                                    ivThumbUp.x = values.animatedValue as Float
                                }
                            },
                            // X轴的移动动画
                            ValueAnimator.ofFloat(ivThumbUp.y, ivThumbUp.y + animatorConfig[index][1]).apply {
                                duration = 700
                                interpolator = DecelerateInterpolator()
                                addUpdateListener { values ->
                                    ivThumbUp.y = values.animatedValue as Float
                                }
                            })
                    }.start()
                }
            }
        }
    }
}

效果如图:

device-2022-12-03-18 -original-original.gif

MotionLayout

MotionLayoutConstraintLayout的子类,包含在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) {
                
            }
        })
    }
}

效果如图:

device-2023-02-04-103100.gif

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

在这里插入图片描述
二、源码解析合集
在这里插入图片描述

三、开源框架合集
在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android实现红心点赞动画的方式有很多种,其中一种比较常见的方式是使用自定义View实现。在这里,我们介绍一种使用开源库FlowLikeView实现点赞动画的方法。 FlowLikeView是一个基于Android的开源库,它提供了一个自定义View,可以实现类似于Instagram的点赞动画效果。它提供了一组可定制的属性和回调,可以让你轻松地将点赞效果集成到你的应用中。 下面是使用FlowLikeView实现红心点赞动画的步骤: 1.添加依赖 在项目的build.gradle文件中添加以下依赖: ``` dependencies { implementation 'com.github.skydoves:flowlikeview:1.1.0' } ``` 2.在layout文件中添加FlowLikeView 在需要添加点赞动画的布局文件中添加FlowLikeView,例如: ``` <com.skydoves.flowlikeview.FlowLikeView android:id="@+id/flowLikeView" android:layout_width="wrap_content" android:layout_height="wrap_content" app:flv_duration="500" app:flv_icon="@drawable/ic_favorite_red_24dp" app:flv_iconSize="24dp" app:flv_textSize="12sp" app:flv_textColor="@color/red" app:flv_textTypeface="sans-serif-medium" /> ``` 在这个例子中,我们设置了FlowLikeView的一些属性,例如动画持续时间、红心图标、文字大小和颜色等。 3.在代码中实现点赞动画 在代码中可以通过调用FlowLikeView的performClick()方法来触发点赞动画,例如: ``` findViewById(R.id.flowLikeView).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ((FlowLikeView)v).performClick(); } }); ``` 这样就可以实现一个基本的红心点赞动画。如果需要更多的自定义,可以查看FlowLikeView的文档和源代码,进行更详细的配置和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值