从源码的角度理解Px/Dp/Sp

Px、Dp和Sp是什么?

其实它们就是个度量单位,

Px表示像素点, 1px = 1像素

Dp和Sp,都表示和屏幕密度无关,不过后者只适用于字体大小。

举个例子,假设:

获取layout的宽度,返回的int数据代表像素值:

int layout_width = contxt.getResource().getDimension(R.dimen.layout_width);

对应dimens.xml文件中的数据为:

<dimen name="layout_width">42dp</dimen>

跟着源码来看是如何获取dp对应的像素值:

    /**
     * Retrieve a dimensional for a particular resource ID.  Unit 
     * conversions are based on the current {@link DisplayMetrics} associated
     * with the resources.
     * 
     * @param id The desired resource identifier, as generated by the aapt
     *           tool. This integer encodes the package, type, and resource
     *           entry. The value 0 is an invalid identifier.
     * 
     * @return Resource dimension value multiplied by the appropriate 
     * metric.
     * 
     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
     *
     * @see #getDimensionPixelOffset
     * @see #getDimensionPixelSize
     */
    public float getDimension(int id) throws NotFoundException {
        synchronized (mAccessLock) {
            TypedValue value = mTmpValue;
            if (value == null) {
                mTmpValue = value = new TypedValue();
            }
            getValue(id, value, true);
            if (value.type == TypedValue.TYPE_DIMENSION) {
                return TypedValue.complexToDimension(value.data, mMetrics);
            }
            throw new NotFoundException(
                    "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
                    + Integer.toHexString(value.type) + " is not valid");
        }
    }

​ 根据英文注释,这个方法,根据id值,返回对应的dimens数据。其中TypeValue是资源数据容器,主要用于Resource类中,主要成员变量有typestringdatadensity等等。

​ 在getValue方法中,由id值来初始化value,这是个jni方法,具体涉及到aapt的资源打包,此处不深入了。有兴趣的话,可以研究下老罗的这篇文章:

Android应用程序资源的编译和打包过程分析

​ getValue完事之后,对value的type进行判断,只有Dimension类型的数据才能调用下一步的方法,毕竟也不能保证误操作getDimension()方法中会不会传进一个字符id。

​ complexToDimension方法最后会调用到applyDimension方法,

public static float applyDimension(int unit, float value,
                                       DisplayMetrics metrics)
    {
        switch (unit) {
        case COMPLEX_UNIT_PX:
            return value;
        case COMPLEX_UNIT_DIP:
            return value * metrics.density;
        case COMPLEX_UNIT_SP:
            return value * metrics.scaledDensity;
        case COMPLEX_UNIT_PT:
            return value * metrics.xdpi * (1.0f/72);
        case COMPLEX_UNIT_IN:
            return value * metrics.xdpi;
        case COMPLEX_UNIT_MM:
            return value * metrics.xdpi * (1.0f/25.4f);
        }
        return 0;
    }

​ 其中,DisplayMetrics也是一个重要的数据容器,记录了重要的显示数据,比如屏幕宽度、高度、密度等。unit数据是从先前的TypeValue的data数据中获取,对了,再重申一遍,我们要返回的是像素值

​ 1.如果unit是PX,直接返回数值;
2.如果是DP,则将数值乘以屏幕像素密度。dp也叫dip(density independent pixel)直译为密度无关的像素。我们猜测如果使用了这个单位,在不同屏幕密度的设备上显示的长度就会是相同的。1dp在mdpi设备下等于1px,在hdpi设备下等于1.5px,同样的在xxhdpi设备下1dp=3px。因此推断出,metrics.density = px值/dp值。
不过设备的密度值是死的,它是一个比例因子,density = 像素值/160, mdpi的像素值为160dpi,因此它的density = 1,所以在mdpi下1dp = 1 px。

​ 因此上述例子中,在mdpi下最终获取的int layout_width = 42,hdpi下是63,以此类推。

​ 3.如果是SP,这个单位和字体大小有关,scaledDensity是系统字体比例因子,在魅族手机的简易模式中,该数值大于1,因此所有应用的字体都看起来很大。

​ 如果你不希望字体大小跟着scaledDensity走怎么办呢?
可以试着setTextSize传入:
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,size, metrics),
unit改为PX就好了,跟着像素走,缺点也是显而易见的,那就是不同屏幕密度,大小也会不一样,只能算一个规避简易模式这个大坑的不得已的处理手段。

​ 剩下的几个单位,PT/IN/ MM,基本用不到,暂时不追踪,等用到的时候再追。哈哈哈。

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

推荐阅读更多精彩内容