Android 设备不仅有不同的屏幕尺寸,手机、平板电脑、电视 等,但也有一些屏幕具有不同的像素尺寸。一个 设备可能每英寸有 160 像素,而另一种设备适合 480 像素 同一空间内的像素。如果您未考虑这些变化 像素密度,系统可能会按比例调整 导致图片模糊不清或 以错误的尺寸显示
本页将向您介绍如何设计您的应用以支持 使用与分辨率无关的测量单位来调整像素密度 并为每种像素密度提供备用位图资源
请观看以下视频,简要了解这些方法。
如需详细了解如何设计图标资源,请参阅 Material Design 图标指南。
使用密度无关像素
避免使用像素来定义距离或尺寸。定义维度 因为不同的屏幕具有不同的像素密度 因此,相同数量的像素 不同设备
<ph type="x-smartling-placeholder">![一张图片,显示密度不同的两个示例设备显示屏](https://developer.android.google.cn/static/images/screens_support/densities-phone_2x.png?authuser=9&hl=el)
保持界面的可见大小 在不同密度的屏幕上时,使用 将密度无关像素 (dp) 作为度量单位。1 dp 表示 虚拟像素单位,在中密度屏幕上大致等于 1 个像素 (160 dpi,或“基准”密度)。Android 会将此值转换为 为每种密度提供适当的实际像素数。
以图 1 中的两台设备为例。符合以下条件的视图: 宽度为 100 像素的设备在左侧显示时要大得多。观看次数 定义为 100 dp 宽,在两个屏幕上具有相同的尺寸。
定义文字大小时,您可以改用可扩展的 像素 (sp) 作为单位。sp 单位为 大小与 dp 相同,但是会根据用户的首选 文字大小。切勿将 sp 用于布局尺寸。
例如,如需指定两个视图的间距,请使用 dp:
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/clickme" android:layout_marginTop="20dp" />
指定文本大小时,请使用 sp:
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="20sp" />
将 dp 单位转换为像素单位
在某些情况下,您需要以 dp 表示尺寸,然后 将其转换为像素。dp 单位到屏幕像素的转换 如下所示:
px = dp * (dpi / 160)
注意:请勿通过硬编码此公式来计算像素,而应使用
TypedValue.applyDimension()
,
它可将许多类型的尺寸(dp、sp 等)转换为像素。
假设有一个应用可以识别滚动或滑动手势
当用户的手指至少移动 16 像素之后。在基准水平
屏幕上,用户的手指必须先移动 16 pixels
/ 160 dpi
,即 1 英寸的 1/10(或 2.5 毫米)
手势识别。
在设备上
配备高密度显示屏 (240 dpi),用户的手指必须移动
16 pixels / 240 dpi
,
等于 1/15 英寸(或 1.7 毫米)。这个距离要短得多,
因此应用对用户来说似乎更灵敏。
要解决此问题,请在代码中以 dp 表示手势阈值, 然后将其转换为实际像素。例如:
Kotlin
// The gesture threshold expressed in dp private const val GESTURE_THRESHOLD_DP = 16.0f private var gestureThreshold: Int = 0 // Convert the dps to pixels, based on density scale gestureThreshold = TypedValue.applyDimension( COMPLEX_UNIT_DIP, GESTURE_THRESHOLD_DP + 0.5f, resources.displayMetrics).toInt() // Use gestureThreshold as a distance in pixels...
Java
// The gesture threshold expressed in dp private final float GESTURE_THRESHOLD_DP = 16.0f; // Convert the dps to pixels, based on density scale int gestureThreshold = (int) TypedValue.applyDimension( COMPLEX_UNIT_DIP, GESTURE_THRESHOLD_DP + 0.5f, getResources().getDisplayMetrics()); // Use gestureThreshold as a distance in pixels...
DisplayMetrics.density
字段
指定用于将 dp 单位转换为
像素。在中等密度屏幕上
DisplayMetrics.density
等于
在高密度屏幕上,此值等于 1.5。在超高密度屏幕上
等于 2.0;在低密度屏幕上,等于 0.75。此数字为
由 TypedValue.applyDimension()
用于
用于获取当前屏幕的实际像素数。
使用预缩放的配置值
您可以使用 ViewConfiguration
类访问常用的
距离、速度和时间例如,
距离(以像素为单位),以获取滚动阈值
使用 getScaledTouchSlop()
:
Kotlin
private val GESTURE_THRESHOLD_DP = ViewConfiguration.get(myContext).scaledTouchSlop
Java
private final int GESTURE_THRESHOLD_DP = ViewConfiguration.get(myContext).getScaledTouchSlop();
ViewConfiguration
中以 getScaled
前缀开头的方法
返回的值(以像素为单位),无论当前
像素密度。
首选矢量图形
除了创建多个特定于密度的图片版本之外,另一种方法是 创建一个矢量图形。矢量图形使用 XML 创建图像, 定义路径和颜色,而不是使用像素位图。因此,矢量 可以缩放到任意尺寸,而不会出现缩放失真 最适合图标,而不是照片等插图。
矢量图形通常以 SVG(可缩放矢量图形)文件的形式提供, 但 Android 不支持此格式,因此您必须将 SVG 文件转换为 Android 的矢量 drawable 格式。
您可以使用 Android Studio 的 Vector Asset Studio 如下所示:
- 在 Project 窗口中,右键点击 res 目录,然后选择 新建 >Vector Asset。
- 选择 Local file (SVG, PSD)。
找到要导入的文件并进行任何调整。
<ph type="x-smartling-placeholder"></ph> <ph type="x-smartling-placeholder">
</ph> 图 2:使用 Android Studio。 您可能会注意到 Asset Studio 窗口中出现了一些错误 表示矢量可绘制对象不支持文件的某些属性。 这不会阻止您导入文件;不受支持的属性 将会被忽略。
点击 Next。
在下一个屏幕上,确认您要将项目中的文件放在哪个源代码集上 然后点击完成。
由于可以对所有像素密度使用一个矢量可绘制对象,因此此文件 放入默认的可绘制对象目录,如以下代码所示 层级结构。您不需要使用密度特定的目录。
res/ drawable/ ic_android_launcher.xml
如需详细了解如何创建矢量图形,请阅读矢量可绘制对象 文档。
提供备用位图
为了在像素密度不同的设备上提供良好的图形质量, 为应用中的每个位图提供多个版本,每个版本各一个 以及相应的分辨率否则,Android 必须扩展 这样位图会在每个屏幕上占用相同的可见空间 例如模糊处理等缩放伪影
<ph type="x-smartling-placeholder">![一张显示不同密度大小的位图相对尺寸的图片](https://developer.android.google.cn/static/images/screens_support/devices-density_2x.png?authuser=9&hl=el)
您的应用中有多个密度级别可供使用。表 1 介绍了可用的不同配置限定符以及 适用的政策
表 1. 针对不同服务 像素密度。
密度限定符 | 说明 |
---|---|
ldpi |
适用于低密度 (ldpi) 屏幕 (~ 120 dpi) 的资源。 |
mdpi |
适用于中密度 (mdpi) 屏幕 (~ 160 dpi) 的资源这是基准 密度。 |
hdpi |
适用于高密度 (hdpi) 屏幕 (~ 240 dpi) 的资源。 |
xhdpi |
适用于超高密度 (xhdpi) 屏幕 (~ 320 dpi) 的资源。 |
xxhdpi |
适用于超超高密度 (xxhdpi) 屏幕 (~ 480 dpi) 的资源。 |
xxxhdpi |
适用于超超超高密度 (xxxhdpi) 屏幕 (~ 640 dpi) 的资源。 |
nodpi |
适用于所有密度的资源。这些是与密度无关的资源。系统不会 缩放带有此限定符的资源,而不考虑当前屏幕的密度。 |
tvdpi |
适用于密度介于 mdpi 和 hdpi 之间的屏幕的资源;大约
约 213 dpi。这不属于“主要”密度组。主要预期用途
而大多数应用都不需要它,因此可以提供 mdpi 和 hdpi
资源足以满足大多数应用的需求,且系统会按需求扩缩资源,
适当的选择。如果您发现有必要提供tvdpi 资源,
按 1.33 * mdpi 的系数调整图片大小。例如,一个 100x100 像素的图片
对于 tvdpi,mdpi 屏幕为 133x133 像素。 |
要针对不同密度创建备用可绘制位图资源,请遵循 六种主要密度之间的缩放比例为 3:4:6:8:12:16。例如,如果你的 一个位图可绘制对象,对于中密度屏幕,为 48x48 像素,尺寸为:
- 36x36 (0.75x) 用于低密度 (ldpi)
- 48x48(1.0x 基准)- 中密度 (mdpi)
- 72x72 (1.5x) - 高密度 (hdpi)
- 96x96 (2.0x) - 超高密度 (xhdpi)
- 144x144 (3.0x) - 超超高密度 (xxhdpi)
- 192x192 (4.0x) - 超超超高密度 (xxxhdpi)
将生成的图片文件放在相应的子目录中
在 res/
下:
res/ drawable-xxxhdpi/ awesome_image.png drawable-xxhdpi/ awesome_image.png drawable-xhdpi/ awesome_image.png drawable-hdpi/ awesome_image.png drawable-mdpi/ awesome_image.png
然后,每当您引用 @drawable/awesomeimage
时,
系统会根据屏幕的 dpi 选择相应的位图。如果您
没有为该密度提供特定于密度的资源,则系统会找到
下一个匹配的高度,并按比例进行缩放以适应屏幕。
提示:如果您有可绘制资源
您不希望系统进行扩缩,例如,在执行
在运行时自行对图片进行一些调整,
包含 nodpi
配置限定符的目录。
带有此限定符的资源会被视为与密度无关,
系统不会对其进行扩缩
如需详细了解其他配置限定符和 Android 如何选择合适的资源来 当前屏幕配置,请参阅应用资源概览。
将应用图标放在 mipmap 目录中
与其他位图资源一样,对于每个位图资源, 您的应用图标。不过,有些应用启动器显示的应用图标最多会有 25% 的比例 大于设备的密度级别所要求的值。
例如,如果设备的密度级别为 xxhdpi,
drawable-xxhdpi
中,应用启动器会放大此图标,
这样会显得不太清晰
为避免出现这种情况,
您的应用图标放在 mipmap
目录(而不是 drawable
目录)中。取消点赞
drawable
目录中,所有 mipmap
目录都会保留在 APK 中,即使
。这样,启动器应用就能选出最佳应用
分辨率图标。
res/ mipmap-xxxhdpi/ launcher_icon.png mipmap-xxhdpi/ launcher_icon.png mipmap-xhdpi/ launcher_icon.png mipmap-hdpi/ launcher_icon.png mipmap-mdpi/ launcher_icon.png
在前面的 xxhdpi 设备示例中,您可以提供一个
mipmap-xxxhdpi
目录中的高密度启动器图标。
如需了解图标设计准则,请参阅系统图标。
如需构建应用图标方面的帮助,请参阅使用 Image Asset Studio 创建应用图标。
针对不常见的密度问题给出的建议
本部分介绍了 Android 如何对位图执行缩放 以及如何进一步控制 位图以不同的密度绘制除非您的应用会操纵图形 或者,您在以不同的像素密度运行时遇到问题, 可以忽略此部分。
为了更好地了解在处理 运行时,您需要了解系统如何帮助确保正确缩放位图。 这可以通过以下方式实现:
- 预缩放资源(如可绘制位图资源)
根据当前屏幕的密度,系统将使用任何特定于密度的屏幕 从您的应用获取资源如果以下集群中没有资源可用: 密度设置正确时,系统会加载默认资源,并根据需要将其放大或缩小。系统会假定默认资源 目录)专为基准测试而设计 像素密度 (mdpi),并将这些位图调整为 当前像素密度。
如果您请求预缩放的资源的尺寸,系统将返回值 表示缩放后的尺寸。例如,设计为 50x50 像素的位图 mdpi 屏幕在 hdpi 屏幕上放大为 75x75 像素(如果没有备用资源) 代表 hdpi),并且系统会这样报告尺寸。
在某些情况下,您可能不希望 Android 预缩放 资源。避免预扩缩的最简单方法是将资源放在资源目录中 替换为
nodpi
配置限定符。例如:res/drawable-nodpi/icon.png
当系统使用此文件夹中的
icon.png
位图时,不会对其进行缩放 根据当前设备密度确定尺寸 - 自动调整像素尺寸和坐标
您可以通过设置
android:anyDensity
来停用预缩放尺寸和图片 设置为"false"
,或者针对Bitmap
以编程方式将inScaled
设置为"false"
。在 在这种情况下,系统会自动缩放所有绝对像素坐标和 尺寸值。这样做是为了确保 屏幕元素仍会以大致相同的物理尺寸显示 确保它们能以基线像素密度 (mdpi) 显示。系统会负责处理 此缩放操作对应用是透明的,并报告缩放后的像素 而不是实际的像素尺寸例如,假设某设备具有 WVGA 高密度屏幕,其尺寸为 480x800, 屏幕大小与传统 HVGA 屏幕相同 - 但它运行的应用已停用 预缩放。在这种情况下,系统会“依赖于”当应用查询屏幕时 尺寸和报告为 320x533,这是像素密度对应的 mdpi 平移的近似值。
然后,当 应用执行绘图操作,例如使 (10,10) 到 (100, 100),系统会通过缩放相应量来改变坐标,而实际上 会使区域 (15,15) 至 (150, 150) 失效。如果存在以下情况,这种差异可能会导致意外行为: 您的应用会直接操控缩放的位图,但这被认为 以确保实现最佳应用性能。如果您遇到这种情况 请阅读将 dp 单位转换为像素 单位。
通常,您不会停用预缩放。支持多种 遵循本页介绍的基本技术。
如果您的应用操控位图或直接与屏幕上的像素互动 您可能需要采取额外步骤来支持 像素密度。例如,如果您通过计数 您需要对手指覆盖的像素数使用适当的值 与密度无关的像素值,而不是实际像素, 在 dp 和 px 值之间进行转换。
针对所有像素密度测试
在采用不同像素的多部设备上测试应用 以便确保界面正确缩放。在实体设备上进行测试 设备;请使用 Android 模拟器。 以适应各种不同的像素密度。
如果您想在实体设备上进行测试 不想购买设备,您可以使用 Firebase 测试实验室 访问 Google 数据中心内的设备。