1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 如何让自定义控件的字体瘦身(优化圆形圆点进度条)

如何让自定义控件的字体瘦身(优化圆形圆点进度条)

时间:2021-02-02 18:54:02

相关推荐

如何让自定义控件的字体瘦身(优化圆形圆点进度条)

一、开源

源码及demo下载

二、产品经理来了

本以为写好的圆形圆点进度条没问题了,因为写前篇博客时优化了一些细节。那位提需求的童鞋下班后呼叫我,说UI有点问题:我的百分比字体偏壮,没原版的苗条(告诉我是百度手机助手,现在才知道⊙﹏⊙b)。

一对比,确实粗壮了不少。

怀疑是不是系统的原因,特意去下载手机助手在同一手机上进行比对,,,确实如此,接下来,找办法解决:

首先去查是不是有字体类型,一个一个试,都不是想要的。

// 系统给的5种字体类型:Typeface.DEFAULT; // 系统默认Typeface.DEFAULT_BOLD;Typeface.SANS_SERIF;Typeface.SERIF;Typeface.MONOSPACE;// 设置字体类型paint.setTypeface(typeface);

问度娘也无果。。。

看代码,突然想Stroke是否可以。但以前测试过,Stroke下绘制文本,setStrokeWidth(w)中的w为0,与Fill一样,非0的话就出现中空文本,类似于“华文彩云”的效果,并不能瘦身。

奇葩灵感突然冒出来:中空文本的颜色变成背景色,然后画到原文本上,这不就瘦身了吗?别说,还真可以,详见瘦身法2,后来也加入到自定义属性中了。

这方法总有点怪怪的,仔细对比图,还发现字体都不一样,拿到Excel中查找,发现:

百分比值,原版的是前面那种,而我的是系统默认的后面那种;原版的单位和按钮文本还是保留了系统默认的。

系统字体库都在这个目录下(别问我Mac):系统盘/Windows/Fonts。就这么轻而易举地找到了,把它拷贝到系统中,AS放到module的src/main/assets/fonts目录下,文件名是ARIALUNI.TTF。

// 获取外部字体库Typeface tf = Typeface.createFromAsset(context.getAssets(), "fonts/ARIALUNI.TTF");paint.setTypeface(tf);

运行结果:

字体OK了,但怎么还这么粗壮?

再看看这个字体库,22M多,百度不可能塞这样大的文件到apk中。本以为在字体库中只留数字就好了,可以用记事本编辑字体库,发现我错了。。。(要不是错了,还真以为是这种字体+抽脂法实现的。看下面的图,抽的还好吧?后面那个)

难道是图片?也不可能,得101张图片,严重浪费资源。

既然字体库太大,不行,就去找找原版的有没有小的字体库。把apk改成后缀zip,里面还真找到两个字体库文件(把文件显示图标放大,在图标上就能看到字体样式),就是你了:HelveticaNeueLTPro.ttf,大小18K,放到module中测试,结果就是上图中的第一个。

竟然还有Arial Unicode MS的缩小版?一万只草泥马灰过。。。

最后,进一步完善:

优化百分比字体显示,使其更瘦小,默认使用外部字体,毕竟人家是大公司,UI肯定厉害添加自定义属性isPercentFontSystem,让开发者可以自己选择使用外部的(默认)还是系统的添加自定义属性percentThinPadding,如果觉得字体大(背景是纯颜色),还可以使用此瘦身针优化绘制按钮时的冗余代码,进行抽取

感谢”产品经理“,让我又学了一招。

三、瘦身法1:更换字体类型

即导入外部字体库(如果有的话):

把外部ttf字体库abc.ttf放在src/main/assets/fonts目录下获取字体库:Typeface tf = Typeface.createFromAsset(context.getAssets(), "fonts/abc.ttf")

若不放在assets中,可通过这两个方法获取:

Typeface.createFromFile(File file)

Typeface.createFromFile(String path)设置字体类型:

paint.setTypeface(tf);

四、瘦身法2:抽脂法

所谓抽脂法,就是把字体周围抽掉一些。方法就是:在使用Fill绘制好文本后,设置画笔颜色为背景色,然后使用Stroke绘制一次文本。

但此方法有使用局限:背景必须是纯颜色,不能是空、透明、图片。

// 2.1.1 对百分比瘦身if (percentThinPadding != 0) {int bgColor = Color.TRANSPARENT;Drawable bgDrawable = getBackground();// 确保有背景,且是纯颜色背景(图片则是BitmapDrawable)if (bgDrawable != null && bgDrawable instanceof ColorDrawable) {bgColor = ((ColorDrawable)bgDrawable).getColor();}if (bgColor != Color.TRANSPARENT) {// 使用Stroke进行瘦身mPaint.setColor(bgColor);mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(percentThinPadding);canvas.drawText(percent + "", mCenterX - textWidth / 2, baseline, mPaint);mPaint.setStyle(Paint.Style.FILL);}}

也把它加入到功能中了。效果如下:

1个小时后补充:

一直觉得不对劲,洗澡时想起来paint画笔是有橡皮擦的。又重新修改代码,使它在适用于任意背景:

// 2.1.1 对百分比瘦身if (percentThinPadding != 0) {// 使用橡皮擦擦除mPaint.setXfermode(mPercentThinXfermode);mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(percentThinPadding);canvas.drawText(percent + "", mCenterX - textWidth / 2, baseline, mPaint);mPaint.setXfermode(null);mPaint.setStyle(Paint.Style.FILL);}

这样才OK:

这次修改,掉入不少坑(不然也不会到现在的3点多了,偶的身体啊!!!):

直接擦除,文本边框成黑色。因为canvas是包括了背景色的,在canvas上擦除,相当于直接把整个控件的颜色擦除,这样会成为黑色。

解决办法:创建一个与控件一样大小的Bitmap,同时用此bitmap创建新画布mCanvas,然后在上面绘制,最后把bitmap绘制到canvas中。onDraw()会被频繁调用,强烈避免在此方法中创建Bitmap和Canvas。

解决办法:在onSizeChanged()中创建,刚好,只要尺寸变化,Bitmap的尺寸也必须变化。每次绘制都是使用同一个bitmap和mCanvas,会导致之前的痕迹都在上面

解决办法:每次绘制前先擦除画布的所有内容。

mClearCanvasXfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);// 先清除上次绘制的mPaint.setXfermode(mClearCanvasXfermode);mCanvas.drawPaint(mPaint);mPaint.setXfermode(null);

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。