View单位转换的秘密(系统源码分析)

上一篇Android之重新推导设备尺寸对屏幕尺寸的概念进行了推算。如果你对设备尺寸的掌握程度还比较模糊,不妨看一看,方便我们继续搞事拉。

在自定义View上做适配,多数情况下可以根据权重和获取整个控件的宽高然后根据百分比去设置某个特殊的属性需要用到的值。but,这些都太常见了。也不是一个我们今天要讲的重点。

不知道大家有没有纠结一个问题,在自定义View里,经常要定义Paint用来绘制。但是setStrokeWidth(float width)里的入参接受的到底是以px? dp? 哪个为单位。这里有本质上的区别。比如你写了一个控件,自己的开发机器没问题,结果换一个设备就尺寸就不准了。

我先卖个关子,不告诉你答案╭(╯^╰)╮。为此我们用官方TextVIew源码和TypedArray源码作为分析。

这是一条温柔的提示:来么,宝贝儿!打开我们的AndroidStudio快速轻击Shift两下,然后输入TextView,我们一起看流星吧。(里面真的有很多小星星都是注释)

目录

  • TextView中的textSize源码分析
  • TypedArray源码分析

TextView中的textSize源码分析

textSize默认大小

我们可以看到默认情况下,TextViewtextSize是15。

重绘方法

而后我发现了这样一个方法,用于重新设置FontSize,这里逻辑很清晰,判断Paint的Size和刚刚重设是否一致,不一致就重设Paint的参数,并重新绘制View。

最后调用的是Native方法,java层已经看不到了。


setTextSize发现TypedValue

不过这些不是重点,我们还发现了另外一个方法。TextVIew设置字体有重载方法。我们重点去看两个参数的。

这里说明了Size的单位大小是由unit来决定的,最后它调用了SetRawTextSize方法,而这个方法我们前面分析了是用来重绘的。我们来看Unit是个什么值。

通过TypedValue类发现实际所有的单位都是定义在这里的。而我们的setTextSize需要的单位也在这里。

TypedValue.applyDimension

重头戏来了,如果我们用了两个参数构造方法进行设置字体大小,那么。
TypedValue.applyDimension( unit, size, r.getDisplayMetrics())做了什
么,他是如何转换单位的。我跟进去看。


我们来看最典型的一条case语句case COMPLEX_UNIT_DIP: return value * metrics.density;
这里的density就是我们上个章节里讲到的密度,也就是说如果你用dp作为单位,他就已当前的size乘以密度返回。
好家伙,恍然大悟把?实际上这里把你传入的任意单位最后都转换成了像素来处理的,最后设置给了Paint

那么这里就说明了一个问题,Paint对象接受的参数最后都是px像素来使用的,不要漏掉了这一点喔。

这里我推荐直接使用TypedValue.applyDimension()来处理。这是android已经具备的Api,不需要自己再从零写了。可能有小伙伴用过类似dp2Px()这种类库。我个人不是很推荐往项目里堆叠繁杂的库进来,一来是会变得越来越臃肿,而是如果单纯的依赖不方便去修改源码,出了问题,你要么选择copy出代码出来进行修改,要么反射一下。但这都不是很优雅。尽可能使用系统已有的。

参考代码:

 TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, Resources.getSystem().getDisplayMetrics());


TypedArray源码分析

什么是TypedArray

如果有常写自定义View属性的小伙伴一定对TypedArray不陌生,我们常用来在Java文件中取自定义View上的属性。这些属性可以是布尔、dp、整型、字符串甚至是一个布局文件的id等。

现在我们思考一个问题,平时在一个控件里描述一个长度用了dp为单位,他是如何适配在不同设备上的?

带着这个疑惑,我们来看源码如何解析的。首先我们不管是原生控件也好,还是自定义控件也好,我们都需要在构造方法中去取出XML布局文件中的属性。

获取TypedArray

这里获取TypedArray对象,其中R.styleable.xxx是该控件拥有的属性。

TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.xxx);  

接着我们来看一眼TypedArray都有那些方法。

TypedArray的使用

实际上,我们的控件从XML中去解析就是通过该TypedArray的API来操作的。见TextView获取textSize源码如下。


我们来看一眼,getDimensionPixelSize方法内部的逻辑。


注意关键的一行TypedValue.complexToDimensionPixelSize( data[index+AssetManager.STYLE_DATA], mMetrics);, 我们跟进去看。


是不是似曾相识?熟悉吧,没错,该方法最终还是调用了TypedValue.applyDimension()进行了单位换算。我们上一章节讲过这个。我就不再展开里面的逻辑了。到这里真相大白。实际上在xml写的dp、pt、px等,最终都要来这里一趟,将其转换为px。再画出来。所以又一次证明了,我们的画图操作都是基于px为单位的。

流程总结

  • 1.xml定义一个属性
  • 2.在构造方法里用TypedArray来get这个属性。
  • 3.调用getDimensionPixelSize()方法获取该属性上的具体值,并转换单位为像素。
  • 4.绘制出来

我们发现它并不复杂,但很多时候往往是没有去阅读过源码,在工作中不能流畅的解决这些问题。
有小伙伴反应说他的自定义View通过java代码设置尺寸就是不能适配,但是通过属性就可以。这里其实就是忘记调用TypedValue.applyDimension( unit, size, r.getDisplayMetrics())方法。
再比如面试过程中再有面试官问如何做适配的时候,你就不会再是背诵面试题上的答案了吧?

题外话,我反对那些所谓的面试宝典类,不是说这些知识的对错性,而是很多新人在学习的过程中往往是囫囵吞枣,出发的目的如果是为了面试通过背诵这些东西,而不理解其中的概念,甚至想都没有想过为什么是这样。这样的结果绝对不是面试官想看到的。也不是我们应该做的。我们慢一点不要紧,多花点时间,不能途一时之快,那些偷过的懒,都是要还的。


如何下次找到我?

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

推荐阅读更多精彩内容