自定义 View 中的文字测量和绘制

jordan-whitt

之前做 LeafLoadingView 的时候,进度到达 100 后,需要将风扇替换为文字。这里的文字当时还是让我头疼了一会的,不过最终用缩放解决了问题。这让我不禁想,安卓 sdk 中肯定有绘制 text 的 api 我不知道,否则绘制文字的时候难点太多了。如果要我自己实现一个简易版的 TextView 根本不可能。

机缘巧合的某天,我在 github 上看一个项目,正巧看到了他们实现一个自定义 View 时测量文本用的方法,看起来挺好用的,google 了一下,今天学习了。

测量单行文本


这个技能相信大部分有过自定义 View 经历的人都学习过了,如果你有一个单行文本需要测量,那么通常你可以使用 TextPaint 或者 Paint 来测量。

例如:

String text = "This is some text."

TextPaint myTextPaint = new TextPaint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
mTextPaint.setColor(0xFF000000);

float width = mTextPaint.measureText(text);
float height = -mTextPaint.ascent() + mTextPaint.descent();

同样的,由于是单行文本,我们也不需要做换行操作,因此只要直接利用 drawText 方法绘制上去就可以了。这样的需求十分简单,相信即使没有接触过自定义 TextView, 也可以很快完成。

如果你是在界面代码中需要测量文本长度的话,那么下面的代码或许可以帮到你:

//在界面代码中测量文本
// 1. 对于显示在已知 TextView 上的文本
Paint paint = textView.getPaint();
// 2. 对于普通的文本
Paint paint = new Paint();
//... 设置各种显示的属性
// 获取到 Paint 对象之后,剩下的测量方式,请参考上面的代码

测量多行文本 - StaticLayout


我们知道利用 drawText 方法绘制文字,是不会自动换行的。如果文本超出容器的限制,多余的部分在屏幕上是不会显示的。因此,如果要利用 drawText 绘制长文本,需要计算长度进行文本截取和换行绘制的操作。这个过程稍微想象一下就让人怠惰起来一点也没有干劲。

这里就该提到我之前说到的新学习的类了—— StaticLayout。StaticLayout 封装了许多有用的方法,同时它也支持自动换行。事实上,TextView 中也使用到了 StaticLayout。

StaticLayout 的构造器中需要传入许多参数,刚刚见到的时候可以说是一头雾水。下面让我们来介绍一下各个参数的含义:

StaticLayout(
    CharSequence source,            //1.需要分行的字符串
    int bufstart,                   //2.需要分行的字符串从第几的位置开始
    int bufend,                     //3.需要分行的字符串到哪里结束
    TextPaint paint,                //4.画笔对象
    int outerwidth,                 //5.layout的宽度,字符串超出宽度时自动换行
    Alignment align,                //6.layout的对其方式,有ALIGN_CENTER, ALIGN_NORMAL, ALIGN_OPPOSITE 三种
    float spacingmult,              //7.相对行间距,相对字体大小,1.5f表示行间距为1.5倍的字体高度
    float spacingadd,               //8.在基础行距上添加多少
    boolean includepad,             //9.是否包含文字上下的空余部分,在某些语言下,切割这些空余部分会导致显示不全,默认为true
    TextUtils.TruncateAt ellipsize, //10.从什么位置开始省略 TextUtils.TruncateAt
    int ellipsizedWidth,            //11.超过多少开始省略,这个值仅用于省略,不影响 Layout 的宽度
    int maxLine                     //12.最大行数
)

上面的参数如果觉得不够清楚,可以查看源码。在 api 23 之后,加入了 Builder 的链式构造,每个构造方法中都有参数的说明,查看十分方便。

构造好之后,就可以直接利用 getHeight 方法计算出 Layout 的高度了。

String text = "This is some text. This is some text. This is some text. This is some text. This is some text. This is some text.";

TextPaint myTextPaint = new TextPaint();
myTextPaint.setAntiAlias(true);
myTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
myTextPaint.setColor(0xFF000000);

int width = 200;
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
float spacingMultiplier = 1;
float spacingAddition = 0;
boolean includePadding = false;

StaticLayout myStaticLayout = new StaticLayout(text, myTextPaint, width, alignment, spacingMultiplier, spacingAddition, includePadding);

float height = myStaticLayout.getHeight(); 

以上。

感谢:
1.stackoverflow - How is StaticLayout used in Android?
2.Android - drawing multiline text on bitmap
3.Usability of BoringLayout

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

推荐阅读更多精彩内容