dp — 基础,Android 中的密度无关像素

作者: IT Sectr 发布日期: 2026-02-25 阅读时间: 7 分钟

我们解释 dp(密度无关像素)的基础知识——Android 中的测量单位,确保 UI 元素在不同像素密度的屏幕上具有相同的物理尺寸。一个 dp 始终相当于屏幕上的 1/160 英寸,无论设备具有高分辨率还是低分辨率。根据 Google Material Design (2025),Android 应用中的所有尺寸都应使用 dp 而非 px 指定,否则界面在不同设备上看起来会有所不同。

要点

  • dp (density-independent pixel) — Android 中的抽象测量单位,相当于屏幕上的 1/160 英寸。
  • 转换公式:px = dp × (dpi / 160)。在 mdpi 屏幕上 1 dp = 1 px,在 xxhdpi 上 1 dp = 3 px。
  • XML 中的所有尺寸(layout_width、padding、margin)都以 dp 为单位。
  • dimens.xml — 用于集中存储 dp 值的 Android 资源文件。
  • 根据 Google Android Performance Guide (2025),使用 dp 代替 px 可消除 90% 的界面适配问题。

Android 中的 dp 是什么?

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 以及视图宽度/高度尺寸的唯一测量单位。

为什么不能使用 px

如果将按钮的宽度设置为 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:有什么区别

dp、px 和 sp — Android 中的三种测量单位,各有其用途。px — 屏幕的物理像素,取决于密度。dp — 用于元素尺寸的密度无关像素。sp — 用于文本的缩放无关像素,额外考虑系统字体大小设置。根据 Material Design (2025),dp 和 sp 之间的区别是可访问性的关键方面:视力差的用户放大字体,sp 值自动调整,而 dp — 不能。

单位全称考虑密度考虑字体设置应用
pxPixel不推荐
dpDensity-independent PixelLayout、padding、边距
spScale-independent Pixel文本大小

dp 与 px 相互转换的公式

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。

BucketDensitydpi 值48 dp 的 px 值16 dp 的 px 值
mdpi1.01604816
hdpi1.52407224
xhdpi2.03209632
xxhdpi3.048014448
xxxhdpi4.064019264

dimens.xml:集中管理尺寸

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)、元素宽度(常量)、头像尺寸和工具栏高度。

XML


<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。

在 Kotlin 和 XML 中以编程方式使用 dp

在 XML 文件中,dp 直接使用:android:layout_width="48dp"。在程序代码 (Kotlin/Java) 中,需要使用 TypedResource 或扩展函数将 dp 转换为 px。TypedResource 提供在运行时处理 dp 的现成方法:getDimensionPixelSize() 返回整数的 px。在 Jetpack Compose 中,dp 是修饰符和布局容器中的标准测量单位。

Kotlin
// 以编程方式将 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。

使用 dp 的 XML 文件

XML

<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 按钮的标准模式。

使用 dp 时的常见错误

根据 Google Play Console (2025) 对 Android 应用的分析,五个最常见的错误是:在 XML 文件中使用 px 而不是 dp、缺少 dimens.xml(值内联编写)、代码中 dp 到 px 的错误转换(使用整数除法)、忽略文本的 sp 以及不通过 sp 考虑系统字体大小设置。整数除法是最危险的错误:在 Kotlin 中 val px = dp * density — 如果 dp 和 density 是 Int,结果也将是 Int,精度丢失。

  • 使用 px 而非 dp — 应用在不同密度的设备上看起来不同。修复:在 XML 中用 dp 替换 px。
  • 内联值 — 尺寸直接写在布局文件中。值重复使维护和更新变得困难。
  • 文本使用 sp — 使用 dp 作为字体大小会忽略用户设置,破坏可访问性。
  • 整数除法 — 在 Kotlin 中 Int 除以 Int 得到 Int,丢失小数部分。始终使用 Float。

常见问题

dp 与 iOS 中的 pt 有何不同?

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 转换为 px?

在 Jetpack Compose 中无需转换——dp 内置于类型系统中。所有修饰符和布局都接受 Dp,而不是 px。如果需要从 dp 获取 px,请使用 density:val px = with(LocalDensity.current) { 16.dp.toPx() }。LocalDensity 提供考虑设备屏幕密度的转换系数。

在 iOS 中是否需要使用 dp?

dp — Android 术语。在 iOS 中,等效的是 pt (points)。Swift 自动使用不依赖于屏幕密度的点。在 UIKit 和 SwiftUI 中,所有尺寸以点为单位指定,系统使用屏幕的 scale factor (UIScreen.main.scale) 将它们转换为 px。原理相同,名称不同。

总结

  • dp — 密度无关像素,Android 中 UI 尺寸的抽象单位,等于 1/160 英寸。
  • 公式:px = dp × (dpi / 160)。在 mdpi 上 1 dp = 1 px,在 xxhdpi 上 1 dp = 3 px。
  • XML 文件中的所有尺寸应以 dp 为单位,文本大小应以 sp 为单位。
  • dimens.xml — 集中存储尺寸。一个更改更新整个界面。
  • 8-point grid:所有尺寸是 8 dp 的倍数,文本间距——4 sp。
  • 在程序代码中使用 TypedResource 或扩展函数进行 dp 到 px 的转换。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读