基于屏幕密度的图片缩放规则

1. 概述

在平时工作的过程中,总是会遇到这样的问题,将一张图片放到drawable、drawable-ldpi、drawable-mdpi、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi或者drawable-xxxhdpi目录中,在app运行时,加载到内存中的图片与资源目录中的图片相比尺寸可能被缩小或者放大,本篇文章就是来解析这个问题的原因。

2. 预备知识

2.1 术语和概念

Screen size(屏幕尺寸):按屏幕对角测量的实际物理尺寸。
为简便起见,Android 将所有实际屏幕尺寸分组为四种通用尺寸:small, normal, large, and extra-large。

Screen density(屏幕密度):屏幕物理区域中的像素量;通常称为dpi(dots per inch)。例如, 与“ normal”或“ high”密度屏幕相比,“ low”密度屏幕在给定物理区域的像素较少。
为简便起见,Android 将所有屏幕密度分组为六种通用密度: low, medium, high, extra-high, extra-extra-high, and extra-extra-extra-high。

Orientation(方向):从用户的角度来看屏幕的方向,即横屏还是竖屏。 请注意,默认情况下不仅不同的设备以不同的方向运行,而且当用户旋转设备时,方向可能会在运行时发生变化。

Resolution(分辨率):屏幕上物理像素的总数。添加对多种屏幕的支持时, 应用不会直接使用分辨率;而只应关注通用尺寸和密度组指定的屏幕尺寸及密度。

Density-independent pixel(密度无关像素 dp):在定义UI布局时应使用的虚拟像素单位,用于以密度无关的方式表示布局尺寸或位置。
一个密度无关像素等于 160 dpi 屏幕上的一个物理像素,“ medium”的屏幕密度为160 dpi。在运行时,系统会根据当前屏幕的实际密度按需要对资源进行适当的缩放 。dp单位转换为屏幕像素很简单: px = dp * (dpi / 160),例如,在 240 dpi 屏幕上,1dp等于 1.5 物理像素。在定义应用UI时应始终使用 dp 单位 ,以确保在不同密度的屏幕上显示UI的大小一致。

2.2 屏幕尺寸和屏幕密度的分类

从 Android 1.6(API 级别 4)开始,Android 支持多种屏幕尺寸和密度,反映设备可能具有的多种不同屏幕配置。 您可以通过Android系统的功能优化应用在各种屏幕配置下的用户界面 ,确保应用不仅正常渲染,而且在每个屏幕上提供最佳的用户体验。

为简化为多种屏幕设计用户界面的方式,Android 将实际屏幕尺寸和密度的范围分为:
1> 四种通用尺寸:small, normal, large, and xlarge
注意:从 Android 3.2(API 级别 13)开始,这些尺寸组已弃用,而采用根据可用屏幕宽度管理屏幕尺寸的新技术。如果为 Android 3.2 和更高版本开发,请参阅声明适用于 Android 3.2 的平板电脑布局以了解更多信息。

2> 六种通用的密度:
ldpi (low) ~120dpi
mdpi (medium) ~160dpi
hdpi (high) ~240dpi
xhdpi (extra-high) ~320dpi
xxhdpi (extra-extra-high) ~480dpi
xxxhdpi (extra-extra-extra-high) ~640dpi

通用的尺寸和密度按照基线配置(即normal尺寸和 mdpi密度)排列。 此基线基于第一代 Android 设备 (T-Mobile G1) 的屏幕配置,该设备采用 HVGA 屏幕(在 Android 1.6 之前,这是 Android 支持的唯一屏幕配置)。

每种通用的尺寸和密度都涵盖一个实际屏幕尺寸和密度范围。例如, 两部都报告normal屏幕尺寸的设备在手动测量时,实际屏幕尺寸和高宽比可能略有不同。类似地,对于两台报告 hdpi 屏幕密度的设备,其实际像素密度可能略有不同。 Android 将这些差异抽象概括到应用,使您可以只提供为通用尺寸和密度设计的UI,让系统按需要做最终调整(具体怎么调整下面第3部分会具体说明)。 下图说明不同的尺寸和密度如何粗略归类为不同的尺寸 和密度组。


说明 Android 如何将实际尺寸和密度粗略地对应到通用的尺寸和密度(数据并不精确)

在为不同的屏幕尺寸设计UI时,您会发现每种设计都需要最小空间。因此,上述每种通用的屏幕尺寸都关联了系统定义的最低分辨率。这些最小尺寸以“dp”单位表示 — 在定义布局时应使用相同的单位 — 这样系统无需担心屏幕密度的变化。
xlarge screens are at least 960dp x 720dp
large screens are at least 640dp x 480dp
normal screens are at least 470dp x 320dp
small screens are at least 426dp x 320dp

要针对不同的屏幕尺寸和密度优化应用的 UI,可为任何通用的尺寸和密度提供备用资源通常,应为不同的屏幕尺寸提供备选布局,为不同的屏幕密度提供备选位图图像。 在运行时,系统会根据当前设备屏幕的通用尺寸或密度匹配适当的资源。

2.3 Density independence

应用显示在密度不同的屏幕上时,如果保持用户界面元素的物理尺寸(从用户的视角)一致,也就实现了“Density independence” 。

保持Density independence很重要,因为如果没有此功能,UI 元素(例如 按钮)在低密度屏幕上看起来较大,在高密度屏幕上看起来较小。这些密度相关的大小变化可能给应用布局和易用性带来问题。下面两张图依次显示了应用不提供Density independence和提供Density independence时的差异。


图2 不支持不同密度的示例应用在低、中、高密度屏幕上的显示情况

图3 良好支持不同密度(密度独立)的示例应用在低、中、高密度屏幕上的显示情况

在图 2 中,文本视图和位图可绘制对象具有以像素(px单位)指定的尺寸,因此视图的物理尺寸在低密度屏幕上更大,在高密度屏幕上更小。这是因为,虽然实际屏幕尺寸可能相同,但高密度屏幕的每英寸像素更多(同样多的像素在一个更小的区域内)。在图 3 中,布局尺寸以密度独立的像素(dp 单位)指定。由于密度独立像素的基线是medium密度屏幕,因此具有medium密度屏幕的设备看起来与图 2 一样,对于low密度(1dp = 0.75px)和high密度(1dp = 1.5px)的屏幕,文本视图和位图可绘制对象的大小与medium密度屏幕相同。

大多数情况下,确保应用中的density independence很简单,只需以适当的密度独立像素(dp 单位)或 "wrap_content" 指定所有布局尺寸值。

3. 基于屏幕密度的图片缩放规则

3.1 匹配规则

假设当前屏幕密度对应的通用分类为xhdpi,系统会优先在drawable-xhdpi目录中寻找需要的drawable资源,如果没有找到,就会依次在drawable-xxhdpi、drawable-xxxhdpi目录中寻找需要的drawable资源,如果还是没有找到,就会到drawable-nodpi中寻找需要的drawable资源,如果还是没有找到,就会依次在drawable-hdpi、drawable-mdpi、drawable、drawable-ldpi目录中寻找需要的drawable资源,如果还是没有找到,那是不可能的,因为这样的话编译都不会过的。

3.2 缩放规则

1> 按照上面的方式找到匹配的drawable资源后,假设当前屏幕密度为x,匹配的drawable资源所在的目录的屏幕密度为y,那就会按照 x/y 比例缩放匹配的drawable资源,以匹配当前的屏幕密度。

2> 对于放在有nodpi配置限定符的drawable资源目录中。例如:res/drawable-nodpi/icon.png,当系统使用此文件夹中的 icon.png 位图时,不会根据当前屏幕密度缩放。

3.3 举例验证:

1> 通过断点的方式获取到手机屏幕密度,如下图所示:



我的手机的屏幕密度为420dpi,对应屏幕密度通用分类中的xxhdpi(480dpi)。

2> 验证3.1 匹配规则
通过在drawable、drawable-ldpi、drawable-mdpi、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxhdpi和drawable-nodpi目录中各放一张名称相同内容不同的图片,可以很容易验证3.1 中的规则,有兴趣的同学可以自己验证一下。

3> 验证3.2 缩放规则
仅在drawable-xxhdpi目录下放置一张图片,图片大小如下图所示:



在不进行缩放的情况下加载到内存中,内存中该图片的大小应该是:
507*760*4 = 1541280 byte
接着将这个图片放到imageview中,通过断点的方式看一下该图片被加载到内存中的实际大小:



可以看到图片的大小被压缩了,根据3.2中的规则计算一下缩小的过程:
缩放后的宽为:(420/480)*507 = 444
缩放后的高为:(420/480)*760 = 665

缩放后的大小为:444*665*4 = 1181040 byte,和上面截图中的大小相同。

下面仅在drawable-hdpi目录下放置一张图片,图片大小如下图所示:



在不进行缩放的情况下加载到内存中,内存中该图片的大小应该是:
700*1049*4 = 2937200 byte
接着将这个图片放到imageview中,通过断点的方式看一下该图片被加载到内存中的实际大小:



可以看到图片的大小被放大了,根据3.2中的规则计算一下放大的过程:
放大后的宽为:(420/240)*700 = 1225

放大后的高为:(420/240)*1049 = 1836
放大后的大小为:1225*1836*4 = 8996400 byte,和上面截图中的大小相同。

下面仅在drawable目录下放置一张图片,图片大小如下图所示:



在不进行缩放的情况下加载到内存中,内存中该图片的大小应该是:
800*577*4 = 1846400 byte
接着将这个图片放到imageview中,通过断点的方式看一下该图片被加载到内存中的实际大小:



由于系统假设默认资源( 没有配置限定符目录中的资源)针对基线屏幕密度 (mdpi) 而设计,因此drawable目录对应的屏幕密度是160dpi。
可以看到图片的大小被放大了,根据3.2中的规则计算一下放大的过程:

放大后的宽为:(420/160)*800 = 2100
放大后的高为:(420/160)*577 = 1515
放大后的大小为:2100* 1515*4 = 12726000 byte,和上面截图中的大小相同。

下面仅在drawable-nodpi目录下放置一张图片,图片大小如下图所示:



在不进行缩放的情况下加载到内存中,内存中该图片的大小应该是:
600*900*4 = 2160000 byte
接着将这个图片放到imageview中,通过断点的方式看一下该图片被加载到内存中的实际大小:



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

推荐阅读更多精彩内容