【view】- 文本跑马灯效果

简介

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

效果图

jjj.gif

Android文本参数 - FontMetrics

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

  • 基准点是baseline

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

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

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

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

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

详情图


204735397.png

简化版图


ll.gif

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


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://blog.csdn.net/aigestudio/article/details/41447349

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容