我们解释 dp(密度无关像素)的基础知识——Android 中的测量单位,确保 UI 元素在不同像素密度的屏幕上具有相同的物理尺寸。一个 dp 始终相当于屏幕上的 1/160 英寸,无论设备具有高分辨率还是低分辨率。根据 Google Material Design (2025),Android 应用中的所有尺寸都应使用 dp 而非 px 指定,否则界面在不同设备上看起来会有所不同。
要点
dp (density-independent pixel) — 是 Android 中的虚拟测量单位,用于统一不同像素密度设备上的 UI 元素尺寸。一个 dp 约等于 160 dpi (mdpi) 屏幕上的一个物理像素。在 320 dpi (xhdpi) 屏幕上,1 dp 等于 2 个物理像素。因此,元素在屏幕上的物理尺寸保持不变——约 1/160 英寸。根据 Android Developers (2025),dp 是应用于 layout、padding、margin 以及视图宽度/高度尺寸的唯一测量单位。
如果将按钮的宽度设置为 160 px,在 mdpi 屏幕上宽度将为 1 英寸,而在 xxxhdpi (640 dpi) 屏幕上仅为 0.25 英寸。dp 解决了这个问题:160 dp 在任何屏幕上都将等于 1 英寸。Android 在渲染时通过 DisplayMetrics.density 自动将 dp 转换为 px。根据 Android Developer Blog (2025),在引入 dp (Android 1.0) 之前,开发人员手动计算 px,导致移植时经常出现错误。
dp、px 和 sp — Android 中的三种测量单位,各有其用途。px — 屏幕的物理像素,取决于密度。dp — 用于元素尺寸的密度无关像素。sp — 用于文本的缩放无关像素,额外考虑系统字体大小设置。根据 Material Design (2025),dp 和 sp 之间的区别是可访问性的关键方面:视力差的用户放大字体,sp 值自动调整,而 dp — 不能。
| 单位 | 全称 | 考虑密度 | 考虑字体设置 | 应用 |
|---|---|---|---|---|
| px | Pixel | 否 | 否 | 不推荐 |
| dp | Density-independent Pixel | 是 | 否 | Layout、padding、边距 |
| sp | Scale-independent Pixel | 是 | 是 | 文本大小 |
dp 转 px 的公式:px = dp × (dpi / 160)。反向转换:dp = px / (dpi / 160)。density 是 dpi / 160 的比率,Android 根据 DisplayMetrics 计算。mdpi 上 density = 1.0,hdpi 上 = 1.5,xhdpi 上 = 2.0,xxhdpi 上 = 3.0,xxxhdpi 上 = 4.0。因此,48 dp 的像素值:mdpi 上 — 48 px,xxhdpi 上 — 144 px。根据 Google I/O 2024,此公式可用于将 iOS pt (points) 近似转换为 dp — 1 pt ≈ 1 dp。
| Bucket | Density | dpi 值 | 48 dp 的 px 值 | 16 dp 的 px 值 |
|---|---|---|---|---|
| mdpi | 1.0 | 160 | 48 | 16 |
| hdpi | 1.5 | 240 | 72 | 24 |
| xhdpi | 2.0 | 320 | 96 | 32 |
| xxhdpi | 3.0 | 480 | 144 | 48 |
| xxxhdpi | 4.0 | 640 | 192 | 64 |
dimens.xml — 位于 res/values/ 的 Android 资源文件,用于以 dp 为单位存储所有尺寸(文本使用 sp)。在 dimens.xml 中集中尺寸可以简化维护:更改 dimens.xml 中的一个值将更新应用所有屏幕上的尺寸。可以为不同密度创建限定符 dimens.xml 文件 (values-hdpi, values-xhdpi)。根据 Android Jetpack Docs (2025),Google 建议在 dimens.xml 中存储间距 (margin, padding)、元素宽度(常量)、头像尺寸和工具栏高度。
<resources>
<dimen name="margin_small">8dp</dimen>
<dimen name="margin_medium">16dp</dimen>
<dimen name="margin_large">24dp</dimen>
<dimen name="avatar_size">48dp</dimen>
<dimen name="toolbar_height">56dp</dimen>
<dimen name="text_size_body">14sp</dimen>
<dimen name="icon_size_small">24dp</dimen>
</resources>
在此文件中,每个 dimen 都有一个名称和值。在 XML 文件中使用:@dimen/avatar_size。根据 Material Design Guidelines (2025),Android 中的基本网格步长为 8 dp (8-point grid)。所有间距、元素尺寸和距离都应是 8 dp 的倍数:8、16、24、32、48、56、64、72 dp。对于文本,步长为 4 sp。
在 XML 文件中,dp 直接使用:android:layout_width="48dp"。在程序代码 (Kotlin/Java) 中,需要使用 TypedResource 或扩展函数将 dp 转换为 px。TypedResource 提供在运行时处理 dp 的现成方法:getDimensionPixelSize() 返回整数的 px。在 Jetpack Compose 中,dp 是修饰符和布局容器中的标准测量单位。
// 以编程方式将 dp 转换为 px
fun Context.dpToPx(dp: Int): Int {
return (dp * resources
.displayMetrics
.density).toInt()
}
// 在 Activity 中使用
val paddingPx = dpToPx(16)
button.setPadding(
paddingPx,
paddingPx,
paddingPx,
paddingPx,
)
// Jetpack Compose:dp 作为内置单位
Modifier
.padding(16.dp)
.size(48.dp)
在此示例中 dpToPx() — Context 的扩展函数,使用 displayMetrics.density 将 dp 转换为 px。在 Jetpack Compose 中,dp 内置于类型系统中,不需要手动转换——编译器在渲染阶段自动将 dp 转换为 px。
<Button
android:layout_width="match_parent"
android:layout_height="48dp"
android:padding="@dimen/margin_medium"
android:textSize="@dimen/text_size_body"
android:text="@string/button_label"
android:layout_marginTop="16dp"
/>
在 XML 中,dp 作为数字的后缀添加——margin_top="16dp"。对于文本,使用 sp —— textSize="@dimen/text_size_body"。@dimen 引用允许集中管理值。使用 match_parent 作为宽度和 48dp 作为高度是 Material Design 按钮的标准模式。
根据 Google Play Console (2025) 对 Android 应用的分析,五个最常见的错误是:在 XML 文件中使用 px 而不是 dp、缺少 dimens.xml(值内联编写)、代码中 dp 到 px 的错误转换(使用整数除法)、忽略文本的 sp 以及不通过 sp 考虑系统字体大小设置。整数除法是最危险的错误:在 Kotlin 中 val px = dp * density — 如果 dp 和 density 是 Int,结果也将是 Int,精度丢失。
常见问题
Android 中的 dp 和 iOS 中的 pt (points) 是等效的测量单位。Android 中的 1 dp 约等于 iOS 中的 1 pt。两个概念都描述了密度无关的点:在密度低的旧设备上 1 dp/pt = 1 px,在现代设备上——2-4 px。基础值的差异:Android 使用 160 dpi 作为基础密度,iOS — 163 dpi,误差小于 2%。
在 Jetpack Compose 中无需转换——dp 内置于类型系统中。所有修饰符和布局都接受 Dp,而不是 px。如果需要从 dp 获取 px,请使用 density:val px = with(LocalDensity.current) { 16.dp.toPx() }。LocalDensity 提供考虑设备屏幕密度的转换系数。
dp — Android 术语。在 iOS 中,等效的是 pt (points)。Swift 自动使用不依赖于屏幕密度的点。在 UIKit 和 SwiftUI 中,所有尺寸以点为单位指定,系统使用屏幕的 scale factor (UIScreen.main.scale) 将它们转换为 px。原理相同,名称不同。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。