为了账号安全,请及时绑定邮箱和手机立即绑定

【Android自定义View】- 文本跑马灯效果

标签:
Android

简介

有些时候,文字过长,或者有多条需要展示的文本时,我们需要将文本进行左右滚动,多条文本时,还得上下滚动以实现展示不同的文本内容。这时候就需要我们自定义view来实现文本跑马灯效果了。

效果图

https://img1.sycdn.imooc.com//5d2c00340001b45300850011.jpg

jjj.gif

Android文本参数 - FontMetrics

当我们要自己绘制文本的时候,怎么去计算文字的宽高,有些时候将本文的绘制起点设置为文本控件的中心点,却发现绘制的文本并不是居中的,下面讲解Android中文本是怎么样确定文本的绘制起点的。

  • 基准点是baseline

  • Ascent是baseline之上至字符最高处的距离

  • Descent是baseline之下至字符最低处的距离

  • Leading文档说的很含糊,其实是上一行字符的descent到下一行的ascent之间的距离

  • Top指的是指的是最高字符到baseline的值,即ascent的最大值

  • bottom指的是最下字符到baseline的值,即descent的最大值

详情图


https://img1.sycdn.imooc.com//5d2c004600014d7a05550312.jpg

204735397.png

简化版图


https://img1.sycdn.imooc.com//5d2c00520001ee7d03190180.jpg

ll.gif

在Android中,文字的绘制都是从Baseline处开始的,Baseline往上至字符最高处的距离我们称之为ascent(上坡度),Baseline往下至字符最底处的距离我们称之为descent(下坡度),而leading(行间距)则表示上一行字符的descent到该行字符的ascent之间的距离,top和bottom文档描述地很模糊,其实这里我们可以借鉴一下TextView对文本的绘制,TextView在绘制文本的时候总会在文本的最外层留出一些内边距,为什么要这样做?因为TextView在绘制文本的时候考虑到了类似读音符号,可能大家很久没写过拼音了已经忘了什么叫读音符号了吧……下图中的A上面的符号就是一个拉丁文的类似读音符号的东西:


https://img1.sycdn.imooc.com//5d2c00700001e01f05510172.jpg

gg.png


文本居中绘制:

// 计算Baseline绘制的起点X轴坐标baseX = (int) (canvas.getWidth() / 2 - textPaint.measureText(TEXT) / 2);// 计算Baseline绘制的Y坐标baseY = (int) ((canvas.getHeight() / 2) - ((textPaint.descent() + textPaint.ascent()) / 2));
canvas.drawText(TEXT, baseX, baseY, textPaint);

思路

  • 单条文本

    private void doSingleLineText(Canvas canvas){
        viewHeight = getMeasuredHeight() + 10;
        viewWidth = getMeasuredWidth();
        contentBound.set(0,0,0,0);
        contentPaint.getTextBounds(singleText, 0, singleText.length(), contentBound);
        xOffset = contentBound.width() - viewWidth;

        Paint.FontMetrics fontMetrics = contentPaint.getFontMetrics();        int textHeight = (int) ((-fontMetrics.ascent - fontMetrics.descent) / 2);
        yStartPos = viewHeight / 2 + maxContentHeight / 4 + textHeight / 4;        if (!hasInited) {
            hasInited = true;
            currentX = 0;
            xStartPos = currentX;
        }        if (xOffset > 0) {
            xOffset += contentTextSize * 2;            if (!isHorizontalRunning) {
                isHorizontalRunning = true;                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                    startHorizontalLoop();
                }
            }
        }
        canvas.drawText(singleText, currentX, yStartPos, contentPaint);
    }    private void startHorizontalLoop() {
        ValueAnimator horizontalScrollAnimator;        if (horizontalOriLeft) {
            horizontalScrollAnimator = ValueAnimator.ofFloat(0, 1);
        } else {
            horizontalScrollAnimator = ValueAnimator.ofFloat(0, -1);
        }        if (horizontalScrollSpeed * xOffset / contentTextSize < 0) {
            isHorizontalRunning = false;            return;
        }
        horizontalScrollAnimator.setDuration(horizontalLoopSpeed * xOffset / contentTextSize);
        horizontalScrollAnimator.setInterpolator(mLinearInterpolator);
        horizontalScrollAnimator.start();
        horizontalScrollAnimator.addUpdateListener(mHorizontalLoopUpdateListener);
        horizontalScrollAnimator.addListener(mHorizontalLoopListenerAdapter);
    }

上面的逻辑其实很简单,可以自己查看,我这里随便说一下,Android文本相关的知识

  • 多条文本

    private void doMultiLineText(Canvas canvas){        if (currentIndex >= contentList.size()) {
            currentIndex = 0;
        }
        viewHeight = getMeasuredHeight();
        viewWidth = getMeasuredWidth();

        String currentString = contentList.get(currentIndex);        int nextIndex = currentIndex + 1;        if (currentIndex + 1 >= contentList.size()) {
            nextIndex = 0;
        }
        String nextString = contentList.get(nextIndex);

        contentBound.set(0,0,0,0);
        contentPaint.getTextBounds(currentString, 0, currentString.length(), contentBound);
        xOffset = contentBound.width() - viewWidth;

        Paint.FontMetrics fontMetrics = contentPaint.getFontMetrics();        int textHeight = (int) ((-fontMetrics.ascent - fontMetrics.descent) / 2);
        yStartPos = viewHeight / 2 + maxContentHeight / 4 + textHeight / 4;        if (!hasVerticalInited) {
            hasVerticalInited = true;
            currentY = yStartPos;
        }        if (xOffset > 0) {            //另外加点留白.设留白两个字宽
            xOffset += contentTextSize * 2;            if (!isHorizontalRunning && !isVerticalRunning) {
                isHorizontalRunning = true;                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                    startHorizontalScroll();
                }
                currentX = 0;
            }
        } else {            if (!isVerticalRunning) {
                isVerticalRunning = true;                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                    startVerticalInterval();
                }
                currentX = 0;
            }
        }
        canvas.drawText(currentString, currentX, currentY, contentPaint);
        canvas.drawText(nextString, 0, currentY + viewHeight, contentPaint);
    }

多条文本,其实是在单条文本的基础上,加了一个向上滚动的动画,当像左滚动结束后,开启向上滚动动画,同时,当前滚动动画的文本index加一,详细代码请查看源码,下面会给出完成的源码地址。



作者:奔跑的平头哥
链接:https://www.jianshu.com/p/2274c401dea9


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消