Android drawable图片适配

Android机型众多,屏幕尺寸、分辨率也有很多种,如何适配各种机型也是Android的技能之一。

适配的目的:

  1. 提高图片显示的质量
  2. 减少图片的内存占用
  3. 减少cpu性能的使用

一·先说mipmap

  1. Android studio在创建App项目里,自动在res里会创建几个mipmap文件夹,里面是几张icon图标
  2. 根据Android官方的描述,mipmap仅仅用于存放APP启动图标,可由Image Asset Studio生成。Image Asset Studio会生成mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi五种尺寸的图标。
  3. 自己使用的图片放在对应的drawable文件夹里
  4. 图标最好不要随意定义尺寸,分辨率过低会模糊,过高徒增APK包大小。各种密度下的图标建议尺寸为

密度

建议尺寸

mdpi

48*48

hdpi

72*72

xhdpi

96*96

xxhdpi

144*144

xxxhdpi

192*192

Android 代码限制图标大小 android图标适配_android

二·drawable图片适配

相关概念

dpi
每英寸点数,全称dots per inch。用来表示屏幕密度,即屏幕物理区域中的像素量。高密度屏幕比低密度屏幕在给定物理区域的像素要多。
ppi:物理每英寸的像素,由硬件确定;dpi是由系统根据ppi来确定的。

dp
即dip,全称device independent pixel。设备独立像素,是一种虚拟像素单位,用于以密度无关方式表示布局维度或位置,以确保在不同密度的屏幕上正常显示UI。在160dpi的设备上,1dp=1px。

density
设备的逻辑密度,是dip的缩放因子。以160dpi的屏幕为基线,density=dpi/160。
getResources().getDisplayMetrics().density

sp

缩放独立像素,全称scale independent pixel。类似于dp,一般用于设置字体大小,可以根据用户设置的字体大小偏好来缩放。

文字不适应dp的原因,Android可以在设置页面设置字体的大小(型号为:小、中、大,可能还有其他型号大小,中型 1sp = 1dp),修改的就是sp

Android 代码限制图标大小 android图标适配_drawable_02


Android 代码限制图标大小 android图标适配_图片适配_03

6种通用密度

Android系统为了简化开发者为多种屏幕设计用户界面的方式,Android将实际屏幕尺寸和范围作了通用规定,称作“根据可用屏幕宽度管理屏幕尺寸的新技术”。
通用密度是以mdpi(中)为基线配置的,此基线基于第一代Android设备(T-Mobile G1)的屏幕配置。
六种通用密度为

密度

dpi范围

dp与px关系(手机通用匹配,不包含全部)

ldpi(低)

~120dpi

(0.75)1dp = 0.75px

mdpi(中)

~160dpi

(1.0)1dp = 1px

hdpi(高)

~240dpi

(1.5)1dp = 1.5px

xhdpi(超高)

~320dpi

(2.0)1dp = 2px

xxhdpi(超超高)

~480dpi

(3.0)1dp = 3px

xxxhdpi(超超超高)

~640dpi

(4.0)1dp = 4px

Android系统图片适配原则

  Android为了更好地优化应用在不同屏幕密度下的用户体验,在项目的res目录下可以创建drawab-[density](density为6种通用密度名)目录,开发者在进行APP开发时,针对不同的屏幕密度,将图片放置于对应的drawable-[density]目录,Android系统会依据特定的原则来查找各drawable目录下的图片。查找流程为:

  1. 先查找和屏幕密度最匹配的文件夹。
    例如,当前设备屏幕密度dpi为160,则会优先查找drawable-mdpi目录;如果设备屏幕密度dpi为420,则会优先查找drawable-xxhdpi目录。
  2. 如果在最匹配的目录没有找到对应图片,就会向更高密度的目录查找,直到没有更高密度的目录。
    例如,在最匹配的目录drawable-mdpi中没有查找到,就会查找drawable-hdpi目录,如果还没有查找到,就会查找drawable-xhdpi目录,直到没有更高密度的drawable-[density]目录。
  3. 如果一直往高密度目录均没有查找,Android就会查找drawable-nodpi目录。
    drawable-nodpi目录中的资源适用于所有密度的设备,不管当前屏幕的密度如何,系统都不会缩放此目录中的资源。
    因此,对于永远不希望系统缩放的资源,最简单的方法就是放在此目录中;同时,放在该目录中的资源最好不要再放到其他drawable目录下了,避免得到非预期的效果。
    如果在drawable-nodpi目录也没有查找到,系统就会向比最匹配目录密度低的目录依次查找,直到没有更低密度的目录。
    例如,最匹配目录是xxhdpi,更高密度的目录和nodpi目录查找不到后,就会依次查找drawable-xhdp、drawable-hdpi、drawable-mdpi、drawable-ldpi。
图片适配查找流程 与 流程图

流程

  举个例子,假如当前设备的dpi是320,系统会优先去drawable-xhdpi目录查找,如果找不到,会依次查找xxhdpi → xxxhdpi → hdpi → mdpi → ldpi。对于不存在的drawable-[density]目录直接跳过,中间任一目录查找到资源,则停止本次查找。

总结一下图片查找过程:优先匹配最适合的图片→查找密度高的目录(升序)→查找密度低的目录(降序)。

流程图

Android 代码限制图标大小 android图标适配_android_04

图片的缩小与放大

  前述说到Android为了能够更好地适配各种屏幕,会依据当前设备的dpi对drawable-[density]目录中的图片进行缩放,那么什么情况下图片被放大,什么情况下图片被缩小呢?
  图片的缩放会消耗一些cpu性能

  • 如果图片所在目录为匹配目录,则图片会根据设备dpi做适当的缩放调整。
  • 如果图片所在目录dpi低于匹配目录,那么该图片被认为是为低密度设备需要的,现在要显示在高密度设备上,图片会被放大。
  • 如果图片所在目录dpi高于匹配目录,那么该图片被认为是为高密度设备需要的,现在要显示在低密度设备上,图片会被缩小。
  • 如果图片所在目录为drawable-nodpi,则无论设备dpi为多少,保留原图片大小,不进行缩放。

缩放计算
那么六种通用密度下的缩放倍数是多少呢?以mdpi为基线,各密度目录下的放大倍数(即缩放因子density)如下

密度

放大倍数

ldpi(低)

0.75

mdpi(中)

1.0

hdpi(高)

1.5

xhdpi(超高)

2.0

xxhdpi(超超高)

3.0

xxxhdpi(超超超高)

4.0

缩放倍数(缩放因子)计算方法:对于任意设备,各drawable-[density]目录下的图片放大倍数的计算公式

Android 代码限制图标大小 android图标适配_android_05

图片缩放后的内存计算
  1. 图片占用的内存与图片显示的控件没有关系。
  2. 图片缩小不会增加内存,会增加cpu的消耗。
  3. 图片放大增加内存,增加cpu的消耗。
  4. 如果图片显示控件的宽高 比 加载到内存的图片宽高(缩放后的图片)更大,则图片会失真

图片内存与宽高的关系:
- 图片内存占用 = bitmap width * bitmap height * 颜色深度(单位Byte)
- 图片的宽高与图片的原始宽高、图片在哪个文件夹、设备dpi有关
- bitmap width = 原始宽高 * 设备dpi / 图片所在文件夹dpi

切图与放的位置

  关于切图的选取,Android官方给的建议,各种密度都给出一套图,分别放置在对应的drawable目录下,这种适配是最好的。但也存在问题,一是这种方式会增大安装包的大小;二是很多公司UI在出图时只会出一套。

  在这种情况下,怎么使用好这一套切图呢?由于目前的Android智能手机的屏幕基本都在1080p了,屏幕的dpi多数都处于320~480,为了更好地适配,同时为了节省内存成本,建议将切图放置在drawable-xxhdpi目录,同时建议UI针对该密度的设备设计切图。

Android TV切图

电视的dpi一般都较低


机顶盒切图放置位置和手机不同

  1. 在TV盒子上,UI 按照给手机出切图的方式导出的 xxhpi、xhdpi、hdpi、mdpi等切图,不能直接放置在对应 dpi 的 drawable 目录下。
  2. 比如,UI 以 1080 * 1920 为基准,导出的一比一的切图,在手机上,对应的是 xxhdpi,因放置到手机的 drawable-xxhdpi 文件夹中。而在机顶盒上(假设机顶盒分辨率为 1280 * 720 160dpi 或 1920 * 1080 240dpi),对应的应该是 hdpi,因放置到 drawable-hdpi 文件夹中,机顶盒需要其他切图,应该以 hdpi 为基准进行放大或缩小出图。

总结:
  为了适配大部分机顶盒,UI 应该按照 1920 * 1080 出图,1920 * 1080 效果图导出的1比1的切图,对应的是 hdpi (而非手机开发时候的 xxhdpi)。给 drawable-xhdpi、drawable-hdpi、drawable-mdpi 的切图。编码时,在 value-w1280p、 value-w960p 下分别设不同的值(value-w960p 下的值可按 value-w1280p 中的值等比例缩放获得)。