Android实用View系列------TextView实现打印机效果

在审美疲劳的今天,如何能开发出一款应用让用户耳目一新呐,适当的动画特效能为你的APP加分不少,这一点在海外的APP上表现颇为明显。今天为大家带来一篇实用的自定义view,就是是TextView实现文字逐个显示(类似打印机打字一样,逐个显示的效果)。

按照惯例,无图无真相
Android实用View系列------TextView实现打印机效果_第1张图片
FadeInTextView.gif

Android实用View系列------TextView实现打印机效果_第2张图片
绘制过程.png

1、开篇

在开始讲解之前先问一下大家,看到这样的一个动画效果,脑海中首先先闪的思路是什么,如果你的UI设计师让你去实现的话,你要怎么做呐,希望读者在思考片刻之后再继续阅读,看看我们的设计思路是不是一样,如果不一样比较一下哪种实现起来更方便,哪种效率更高,欢迎评论交流。你有一个思想,我有一个思想,交换一下我们都有两个思想。

当你读到这里的时候说明你应该思考过上边的问题了,就问你第一想法是不是网上搜相关资料,看看有没有现成的,有的话直接拿来,没的话换个方式继续搜索。。。比如到各个开发群里询问有没有类似效果的demo之类的。。。
Android实用View系列------TextView实现打印机效果_第3张图片
城市套路深,我要回农村.jpg

哈哈,开个玩笑啦,第一时间去网上搜索不见得不好,汲取各个大神设计思路之精华嘛,不过我好想近期没这么做哦,因为被伤过,曾经也是一有问题就直接复制到网上和各个开发群询问,但大部分得到的反馈都是没人叼,记得收到回复最多的是这张图!有种被鄙视的感觉有没有。

Android实用View系列------TextView实现打印机效果_第4张图片
程序猿看到这张图内心是崩溃的.jpg

2、实现

扯了半天蛋,终于步入正题了。

其实这样的效果实现思路还是挺多的,有的是动态生成多个TextView,每次设置一个字符控制显示隐藏,有的继承自View完全自定义,从头绘制到底。这里我的方式是继承自TextView,我们只需实现文字逐个显示的效果的逻辑就ok了,至于设置文字颜色,字体大小之类的属性我们直接使用TextView自己属性就好了,这样大大简化了我们的开发流程。

实现步骤:

1、重写onDraw方法,绘制文字
2、利用属性动画在固定时间内重绘显示的文字
3、封装并暴露外部调用的方法

2.1 、重绘文字

    @Override
    protected void onDraw(final Canvas canvas) {
        super.onDraw(canvas);
        if (stringBuffer != null) {
            drawText(canvas, stringBuffer.toString());
        }
    }

stringBuffer就是需要绘制的文字

    /**
     * 绘制文字   
     *           
     * @param canvas 画布
     */
    private void drawText(Canvas canvas, String textString) {
         //设置文字绘制的区域
        textRect.left = getPaddingLeft();
        textRect.top = getPaddingTop();
        textRect.right = getWidth() - getPaddingRight();
        textRect.bottom = getHeight() - getPaddingBottom();
        Paint.FontMetricsInt fontMetrics = getPaint().getFontMetricsInt();
        int baseline = (textRect.bottom + textRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
        //文字绘制到整个布局的中心位置
        canvas.drawText(textString, getPaddingLeft(), baseline, getPaint());
    }

看过我之前写的那几篇文章的朋友会发现我们自定义view系列的文章基本都有这个方法,可以封装一下,以后在任何需要使用的地方都可以拿来直接使用。这个方法没什么复杂的逻辑我们不过多解读了。

2.2、利用属性动画动态改变绘制的文字

代码很好理解先上代码,跟着代码我们去学习实现思路

   /**
     * 文字逐个显示动画  通过插值的方式改变数据源
     */
    private void initAnimation() {

        //从0到textCount - 1  是设置从第一个字到最后一个字的变化因子
        textAnimation = ValueAnimator.ofInt(0, textCount - 1);
        //执行总时间就是每个字的时间乘以字数
        textAnimation.setDuration(textCount * duration);
        //匀速显示文字
        textAnimation.setInterpolator(new LinearInterpolator());
        textAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int index = (int) valueAnimator.getAnimatedValue();
                //过滤去重,保证每个字只重绘一次
                if (currentIndex != index) {
                    stringBuffer.append(arr[index]);

                    currentIndex = index;
                    //所有文字都显示完成之后进度回调结束动画
                    if (currentIndex == (textCount - 1)) {
                        if (textAnimationListener != null) {
                            textAnimationListener.animationFinish();
                        }
                    }

                    invalidate();
                }
            }
        });
    }

思路是这样的:为每个文字显示的时间设置一个固定值duration,我这里默认显示300毫秒,动画执行的总时间就是总共的字数乘以每个字显示的时间( textCount * duration),ValueAnimator.ofInt(0, textCount - 1)是为了根据这个字数的因子当做下标获取单个字符,每次追加到 stringBuffer.append(arr[index]),代码中我做了过滤重绘的判断,保证每次只绘制一遍,提升性能,因为我们的valueAnimator.getAnimatedValue()这个变化因子会不断变化及时转成int类型,每次也是有很多重复的,所以去重这一步就显得格外重要,我们可以看一下打印日志。

Android实用View系列------TextView实现打印机效果_第5张图片
index每次的变化,看到这个就知道去重的重要性了.png
Android实用View系列------TextView实现打印机效果_第6张图片
去重后保证每增加一个字符只绘制一次.png

看到这里其估计有人会问怎么设置要显示的字符串呐还有arr[index]十个什么鬼,不要着急,继续往下看就明白了

    /**
     * 设置逐渐显示的字符串
     *
     * @param textString
     * @return
     */
    public FadeInTextView setTextString(String textString) {
        if (textString != null) {
            //总字数
            textCount = textString.length();
            //存放单个字的数组
            arr = new String[textCount];
            for (int i = 0; i < textCount; i++) {
                arr[i] = textString.substring(i, i + 1);
            }
            initAnimation();
        }

        return this;
    }

我把传入的字符串都存放到一个数组里边每次根据index去取相应的字符,好啦,到此这个功能的实现已经完成了。

3、对外暴露的方法

设置字符的方法少不了,接下来开启动画和停止动画,然后就是动画结束的回调。

  
    /**
     * 开启动画
     *
     * @return
     */
    public FadeInTextView startFadeInAnimation() {
        if (textAnimation != null) {
            //动画开启的时候参数都设置成初始状态
            stringBuffer.setLength(0);
            currentIndex = -1;
            textAnimation.start();
        }
        return this;
    }

    /**
     * 停止动画
     *
     * @return
     */
    public FadeInTextView stopFadeInAnimation() {
        if (textAnimation != null) {
            textAnimation.end();
        }
        return this;
    }

    /**
     * 回调接口
     */
    public interface TextAnimationListener {
        void animationFinish();
    }

4、如何使用

        fadeInTextView
                .setTextString("自定义view实现字符串逐字显示")
                .startFadeInAnimation()
                .setTextAnimationListener(new FadeInTextView.TextAnimationListener() {
                    @Override
                    public void animationFinish() {
                        
                    }
                });

至此本篇文章的介绍已经结束,接下来会继续推出相关系列的文章。小功能大智慧,功能再小还要新手敲一敲,不然。。。不然。。。看图意会吧,哈哈!

Android实用View系列------TextView实现打印机效果_第7张图片
语言上的老司机,行动上的大怂逼.jpg

github源码地址传送门


谨以此篇来记录自己项目中遇到的问题,献给需要类似功能的小伙伴们。如果你有好的建议欢迎评论指出,大家一起讨论、学习、进步!

你可能感兴趣的:(Android实用View系列------TextView实现打印机效果)