那些值得你去细细研究的Drawable适配(上)

话说前段时间我写了一篇drawable微技术的文章,也是引起了不小的反响,因为讲的东西是大家天天在使用,但却偏偏却没有深入了解的知识。而本篇文章的投稿者 王月半子 表示“不服”,看完我写的那篇之后自己也忍不住写了一篇,我阅读之后发现写的挺棒,于是邀请他来公众号上投稿。由于本篇文章内容较长,因此分为上下两篇发表。


王月半子的博客地址:http://blog.csdn.net/wrg_20100512




Android适配的问题太多,有屏幕尺寸的适配、屏幕分辨率的适配以及不同系统版本的适配。反映在代码上,就是需要在资源文件上下功夫,主要是layout和drawable目录下的文件,这里主要研究一下drawable的适配。首先我们先熟悉一下基本的概念。


Android中的长度单位


px(pixel)

表示屏幕实际的像素。例如,1200×1920的屏幕在横向有1200个像素,在纵向有1920个像素。


dpi(dot per inch)

表示屏幕密度是指每英寸上的像素点数。Android将根据不同的dpi将Android设备分成多个显示级别。具体如下:


正如drawable目录和mipmap目录有ldpi、mdpi、hdpi、xhdpi、xxhdpi之分。


*这里解释一下mipmap和drawable的区别

在Android studio开发中,新建一个module的时候不同于Eclipse(会生成drawable、drawable-ldpi、drawable-mdpi、drawable-hxpi等等),在资源文件中会生成mipmap-hdpi、mipmap-mdpi、mipmap-xhdpi、mipmap-xxhdpi和一个drawable目录。


对于这个问题谷歌官方有说法:


drawable/

For bitmap files (PNG, JPEG, or GIF), 9-Patch image files, and XML files that describe Drawable shapes or Drawable objects that contain multiple states (normal, pressed, or focused). 

意思是说以drawable开头的目录存放的文件有png、jpeg、gif格式图片文件、.9图片以及一些XML文件。


mipmap/

For app launcher icons. 

而以mipmap开头的目录存放的是App的图标。


dp

也叫dip(density independent pixel)直译为密度无关的像素。我们猜测如果使用了这个单位,在不同屏幕密度的设备上显示的长度就会是相同的。那么在屏幕上显示图像时都是在屏幕上填充像素点,而使用这种与密度无关的像素(我们在布局文件中使用的 dp/dip 就是与密度无关的像素)是如何转换成像素的呢?其实在Android中,将屏幕密度为160dpi的中密度设备屏幕作为基准屏幕,在这个屏幕中,1dp=1px。其他屏幕密度的设备按照比例换算,具体如下表:

由上表不难计算1dp在hdpi设备下等于1.5px,同样的在xxhdpi设备下1dp=3px。这里我们从dp到px解释了Android中不同屏幕密度之间的像素比例关系。


下面换一个角度,从px到dp的变化来说明这种比例关系。


这里我们选择在以mipmap开头的目录中设计一个icon,要求icon在屏幕中占据相同的dp。那么对于不同的屏幕密度(MDPI、HDPI、XHDPI、XXHDPI 和 XXXHDPI)应按照 2:3:4:6:8 的比例进行缩放。比如尺寸为48x48dp,这表示在 MDPI 的屏幕上其实际尺寸应为 48x48px,在 HDPI 的屏幕上其实际大小是 MDPI 的 1.5 倍 (72x72 px),在 XDPI 的屏幕上其实际大小是 MDPI 的 2 倍 (96x96 px),依此类推。


*图片的描述有两种:

1、仅仅通过宽高的像素。

2、通过图片分辨率(不同于屏幕分辨率,单位英寸中所包含的像素点数)和尺寸大小。


sp(scale-independent pixels)

与dp类似,但是可以在设置里面调节字号的时候,文字会随之改变。当系统字号设为“普通”时,sp与px的尺寸换算和dp与px是一样的。


屏幕尺寸、屏幕分辨率、屏幕密度


屏幕尺寸

设备的物理屏幕尺寸,指屏幕的对角线的长度,单位是英寸,1 inch = 2.54 cm。比如“5寸大屏手机”,就是指对角线的尺寸,5寸×2.54厘米/寸=12.7厘米。


屏幕分辨率

也叫显示分辨率,是屏幕图像的精密度,是指屏幕或者显示器所能显示的像素点有多少。一般以横向像素×纵向像素表示分辨率,如1200×1920表示此屏幕在宽度方向有1200个像素,在高度方向有1920个像素。


屏幕密度

是指每英寸上的像素点数,单位是dpi(dot per inch)或者ppi(pixels per inch),数值越高显示越细腻。屏幕密度与屏幕尺寸和屏幕分辨率有关。例如在屏幕尺寸一定的条件下,屏幕分辨率越高屏幕密度越大,反之越小。同理在屏幕分辨率一定的条件下,屏幕尺寸越小屏幕密度越大,反之越小。


屏幕尺寸和屏幕分辨率,这两个值是可以直接得到的。屏幕密度需要我们计算得到。例如我的手机的分辨率是1200×1920,屏幕尺寸是7寸的。根据屏幕尺寸、屏幕分辨率和屏幕密度定义不难看出他们之间的关系如下图:


根据勾股定理,我们得出对角线的像素数大约是2264,那么用2264除以7就是此屏幕的密度了,计算结果是323。


*备注: 

上面的出现的0.75,1,1.5,2,3,4才是屏幕密度(density)。而120,160,240,320,480,640是屏幕密度dpi(densityDpi)。


实际密度与系统密度

实际密度就是我们自己算出来的密度,这个密度代表了屏幕真实的细腻程度,如上述例子中的323dpi就是实际密度,说明这块屏幕每寸有323个像素。7英寸1200×1920的屏幕密度是323,5英寸1200×1920的屏幕密度是452,而相同分辨率的4.5英寸屏幕密度是503。如此看来,屏幕密度将会出现很多数值,呈现严重的碎片化。而密度又是Android屏幕将界面进行缩放显示的依据,那么Android是如何适配这么多屏幕的呢?


其实,每部Android手机屏幕都有一个初始的固定密度,这些数值是120、160、240、320、480,这些就是Android为不同设备设定的系统密度。


得到实际密度以后,一般会选择一个最近的密度作为系统密度,系统密度是出厂预置的,如440dpi的系统密度就是和它最接近的480dpi;如果是330dpi的设备,它的系统密度就是320dpi。但是,现在很多手机不一定会选择这些值作为系统密度,而是选择实际的dpi作为系统密度,这就导致了很多手机的dpi也不是在这些值内。例如小米Note这样的xxhdpi的设备他的系统密度并不是480,而是它的实际密度440。


获取设备的上述属性

Android系统中有个DisplayMetrics的类,通过这个类就可以得到上述的所有属性。

DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
float density = displayMetrics.density; //屏幕密度
int densityDpi = displayMetrics.densityDpi;//屏幕密度dpi
int heightPixels = displayMetrics.heightPixels;//屏幕高度的像素
int widthPixels = displayMetrics.widthPixels;//屏幕宽度的像素
String screenResolution = widthPixels + "X" + heightPixels;
float scaledDensity = displayMetrics.scaledDensity;//字体的放大系数
float xdpi = displayMetrics.xdpi;//宽度方向上的dpi
float ydpi = displayMetrics.ydpi;//高度方向上的dpi

其中xdpi = ydpi = densityDpi.打印结果如下:


上面计算的我的设备的dpi为323。这里系统给定的屏幕密度dpi为320。


OK,基础的东西介绍完了,那么回归正题:


1. android项目中那么多以drawable开头的文件夹,那应用的配图应该放在哪个文件夹之下呢?

一般的开发的话,都会做三套配图,对应着drawable-hdpi、drawable-xhdpi、drawable-xxhdpi三个文件夹。


2. 那要是做一套呢?应该做哪一套呢?

做一套也是可以的,放在drawable-xxdpi文件夹中。


3. 为什么做一套配图要放在drawable-xxdpi文件夹中?

这里先不给出答案,我在网上也看了一些说法,说是省内存,这里暂且不置可否。


明天我们就从内存的角度去分析问题3,使用同一张图片,放置在不同的drawable文件夹,在同一设备上运行,研究一下图片大小及内存的占用。




如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值