记录一次自定义动效组件

android 酷炫文案随机归位动效实现

 记录一次自定义控件的实现原理

动画效果分解为一个随机位置归位动效和一个渐变的动效

1.根据文案在onSizechange方法里生成一个随机位置的集合和一个最终位置的集合 用于记录每个字符的位置

2.监听valueanimation动态计算随机位置当前应该到达的位置然后重绘界面

3.监听动效结束开始初始化一个渐变的动效 使用LinearGradient和Matrix实现渐变效果 渐变效果实现参考文末链接

 

关键代码如下

@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        initTranslateAnimation(w, h);
    }

    private void initTranslateAnimation(int w, int h) {
        int startX;
        int centerY;
        float contenWith = mPaint.measureText(contentStr);
        Rect rect = new Rect();
        mPaint.getTextBounds(contentStr, 0, contentStr.length(), rect);
        startX = (int) ((w - contenWith) / 2);
        centerY = (h + rect.height()) / 2;
        queitList.clear();
        randowList.clear();
        for (int i = 0; i < contentStr.length(); i++) {
            char c = contentStr.charAt(i);
            float singleW = mPaint.measureText(String.valueOf(c));
            //记录每个字符的开始坐标 (文字绘制的左下角坐标)
            queitList.add(new PointF(startX, centerY));
            // 生成随机位置坐标
            randowList.add(new PointF((float) Math.random() * (w - singleW) + singleW, (float) Math.random() * (h - rect.height()) + rect.height()));
            startX += (singleW + 3);
        }

        animator = ValueAnimator.ofFloat(0, 1);
        animator.setDuration(2000);
        TimeInterpolator intercept = new DecelerateInterpolator(0.05f);
        animator.setInterpolator(intercept);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 计算当前文字的坐标并重绘
                float value = (float) animation.getAnimatedValue();
                for (int i = 0; i < randowList.size(); i++) {
                    PointF pointF = randowList.get(i);
                    PointF pointF1 = queitList.get(i);

                    pointF.x = pointF.x + (pointF1.x - pointF.x) * value;
                    pointF.y = pointF.y + (pointF1.y - pointF.y) * value;
                }
                postInvalidate();
            }
        });
        // 检听归位动画结束开始渐变动画
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                isTranslateEnd = false;
            }

            @Override
            public void onAnimationEnd(Animator animation) {

                isTranslateEnd = true;

                initLightAnimation();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

        animator.start();
    }

    private void initLightAnimation() {
        float strW = mPaint.measureText(contentStr);
        PointF pointF = queitList.get(0);
        // 从文案内容前面开始渐变 注意TileMode.CLAMP 时为了文字颜色不会突变 开始和结束的颜色和textColor保持一致
        final Shader shader = new LinearGradient(pointF.x-strW, 0, pointF.x, 0, new int[]{Color.BLACK,Color.RED,Color.WHITE,Color.BLACK}, null,Shader.TileMode.CLAMP);
        final Matrix matrix = new Matrix();
        shader.setLocalMatrix(matrix);
        mPaint.setShader(shader);
        //
        ValueAnimator animator = ValueAnimator.ofFloat(0, getWidth()*2);
        animator.setDuration(1000);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //计算Matrix translate距离
                float value = (float) animation.getAnimatedValue();
                matrix.setTranslate(value, 0);
                shader.setLocalMatrix(matrix);
                postInvalidate();
            }
        });
        animator.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRect(0, 0, getWidth(), getHeight(), mPaints);
        for (int i = 0; i < contentStr.length(); i++) {
            PointF pointF = isTranslateEnd ? queitList.get(i) : randowList.get(i);
            canvas.drawText(String.valueOf(contentStr.charAt(i)), pointF.x, pointF.y, mPaint);
        }
    }

//开始动效方法
  public void start() {
        if (animator.isRunning()) {
            animator.cancel();
        }
        initTranslateAnimation(getWidth(), getHeight());
    }

 

 

参考文献

https://blog.csdn.net/u012702547/article/details/50821044

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值