美文网首页
Android仿抖音、微视关注动画

Android仿抖音、微视关注动画

作者: 聂傻傻 | 来源:发表于2020-03-11 16:04 被阅读0次

抖音和微视的关注动画差不多,大同小异,话不多说,直接上效果图

实际效果图

动画组成:

1.点击关注的时候,开始会有一个放大的动画

2.关注成功☑️的动画

3.缩放消失的动画

核心实现方式:

1.自定义View

2.PathMeasure和PathEffect

代码如下:

class FollowAnimationButton : View {

    private var rectRadius = 0f
    private var rect: RectF = RectF()
    private var rectPaint: Paint = Paint()
    private var plusPaint: Paint = Paint()
    private var plusLineWidth = 0f
    private var plusPath = Path()

    private var okPaint = Paint()
    private var okLineWidth = 0f
    private var okPath = Path()
    private var pathMeasure: PathMeasure? = null
    private var startDrawOk = false

    private var animatorDrawOk: ValueAnimator? = null

    private var effect: PathEffect? = null
    private var isAnimating = false

    constructor(context: Context) : super(context) {
        init(context)
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        init(context)
    }

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        init(context)
    }

    private fun init(context: Context) {
        rectRadius = CommonUtil.dip2px(context, 15f).toFloat()
        plusLineWidth = CommonUtil.dip2px(context, 2f).toFloat()

        rectPaint.isAntiAlias = true
        rectPaint.color = 0xFFEE0051.toInt()
        rectPaint.style = Paint.Style.FILL

        plusPaint.isAntiAlias = true
        plusPaint.color = Color.WHITE
        plusPaint.style = Paint.Style.STROKE
        plusPaint.strokeWidth = plusLineWidth

        okLineWidth = CommonUtil.dip2px(context, 2.5f).toFloat()
        okPaint.isAntiAlias = true
        okPaint.color = 0xFFEE0051.toInt()
        okPaint.style = Paint.Style.STROKE
        okPaint.strokeWidth = okLineWidth
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        val plusSize = measuredHeight * 0.6f
        plusPath.moveTo(measuredWidth / 2f, (measuredHeight - plusSize) / 2)
        plusPath.lineTo(measuredWidth / 2f, (measuredHeight + plusSize) / 2)
        plusPath.moveTo((measuredWidth - plusSize) / 2, measuredHeight / 2f)
        plusPath.lineTo((measuredWidth + plusSize) / 2, measuredHeight / 2f)

        okPath.moveTo(measuredWidth * 0.31f, measuredHeight * 0.5f)
        okPath.lineTo(measuredWidth * 0.45f, measuredHeight * 0.75f)
        okPath.lineTo(measuredWidth * 0.68f, measuredHeight * 0.25f)
        pathMeasure = PathMeasure(okPath, true)
    }

    override fun onDraw(canvas: Canvas) {

        rect.apply {
            left = 0f
            top = 0f
            right = measuredWidth.toFloat()
            bottom = measuredHeight.toFloat()
        }

        //画勾
        if (startDrawOk) {
            rectPaint.color = Color.WHITE
            canvas.drawRoundRect(rect, rectRadius, rectRadius, rectPaint)
            canvas.drawPath(okPath, okPaint)
        } else {
            rectPaint.color = 0xFFEE0051.toInt()
            canvas.drawRoundRect(rect, rectRadius, rectRadius, rectPaint)
            //加号
            canvas.drawPath(plusPath, plusPaint)
        }

    }

    fun startFollowAnimation(animationEnd: () -> Unit) {
        isAnimating = true
        val startScaleAnimation = ScaleAnimation(1f, 1.2f, 1f, 1.2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f)
        startScaleAnimation.duration = 300
        startScaleAnimation.setAnimationListener(object : AnimationListenerAdapter() {
            override fun onAnimationEnd(animation: Animation?) {
                super.onAnimationEnd(animation)
                startDrawOk = true
                animatorDrawOk = ValueAnimator.ofFloat(1f, 0f).apply {
                    duration = 1000
                    addUpdateListener {
                        val value = it.animatedValue as Float
                        effect = DashPathEffect(floatArrayOf(pathMeasure!!.length, pathMeasure!!.length), value * pathMeasure!!.length)
                        okPaint.pathEffect = effect
                        invalidate()
                    }
                    addListener(object : AnimatorListenerAdapter() {
                        override fun onAnimationEnd(animation: Animator?) {
                            super.onAnimationEnd(animation)
                            val animationSet = AnimationSet(true)
                            val alphaAnimation = AlphaAnimation(1f, 0.2f)
                            val scaleAnimation = ScaleAnimation(1f, 0.2f, 1f, 0.2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f)
                            animationSet.addAnimation(alphaAnimation)
                            animationSet.addAnimation(scaleAnimation)
                            animationSet.duration = 300
                            animationSet.interpolator = AccelerateInterpolator()
                            animationSet.setAnimationListener(object : AnimationListenerAdapter() {
                                override fun onAnimationEnd(animation: Animation?) {
                                    super.onAnimationEnd(animation)
                                    startDrawOk = false
                                    isAnimating = false
                                    animationEnd()
                                }
                            })
                            startAnimation(animationSet)
                        }
                    })
                    start()
                }
            }
        })
        startAnimation(startScaleAnimation)
    }

    fun isAnimating(): Boolean {
        return isAnimating
    }
}

相关文章

网友评论

      本文标题:Android仿抖音、微视关注动画

      本文链接:https://www.haomeiwen.com/subject/muocjhtx.html