2.2 dp、sp与屏幕适配


2.2 dp、sp 与屏幕适配

本节摘要:屏幕适配的核心是三组单位——px(物理像素)、dp(密度无关像素)、sp(可缩放像素)。换算公式:px = dp × dpi ÷ 160。布局尺寸一律用 dp、字号一律用 sp,界面才能在不同密度的屏幕上呈现一致的物理大小。本节从像素密度讲起,把换算、限定符适配、常见坑一次讲透。

一台手机到底有多"密"

先把概念摆正。分辨率是屏幕的像素总数,比如 1080×2400;尺寸是对角线物理长度(英寸);像素密度 dpi(dots per inch)= 对角线像素数 ÷ 对角线英寸数。同样 1080px 宽,6.7 英寸大屏的 dpi 低、5.0 英寸小屏的 dpi 高——像素数相同,物理大小却不同。这就是"在 XML 里写 px"注定失控的原因:100px 在高密度屏上只是一小条,在低密度屏上却宽得出格。

Android 给屏幕密度分了六档,写适配前先背下这张表:

密度档 dpi 范围 1dp 等于多少 px
ldpi ~120 0.75px
mdpi ~160 1px(基准)
hdpi ~240 1.5px
xhdpi ~320 2px
xxhdpi ~480 3px
xxxhdpi ~640 4px

系统以 mdpi(160dpi)为基准:px = dp × dpi ÷ 160。验证一下:48dp 的触摸目标在 xxhdpi(480dpi)屏上 = 48 × 3 = 144px;在 hdpi(240dpi)屏上 = 72px。像素数差了一倍,但两台机器上按出来的物理面积几乎一样——这就是"密度无关"的含义。

dp 与 sp:一字之差

dp 解决布局尺寸,sp 解决文字。二者换算规则相同,唯一区别:sp 会跟随用户在系统设置里调整的字体大小缩放。用户把系统字号调到最大,用 sp 的文字跟着变大,用 dp 的纹丝不动。因此铁律是——凡是字号,一律 sp;凡是间距、控件尺寸、边框,一律 dp;px 基本只在代码里算位图时出现。

<!-- 单位使用的标准姿势 --> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="猜数字" android:textSize="28sp" <!-- 字号用 sp --> android:layout_marginTop="16dp" <!-- 间距用 dp --> android:paddingStart="12dp" /> <Button android:layout_width="wrap_content" android:layout_height="48dp" <!-- 触摸目标高度至少 48dp --> android:minWidth="48dp" android:text="猜!" />

图:同一 100dp 按钮在不同密度屏幕上的像素数

图:同一 100dp 按钮在不同密度屏幕上的像素数

超出 dp:宽度限定符与比例分配

dp 只保证"大小一致",不保证"布局合理"。同一界面在 320dp 宽的手机和 720dp 宽的平板上,控件会拉得忽宽忽窄。Android 的对策是资源限定符:为不同最小宽度提供不同目录的布局文件,系统按设备自动选用。目录名形如"最小宽度 600 以上"的修饰后缀,平板进入该项目时读平板专属布局。

另一个轻量手段是 weight 比例分配(第 4 章详讲),让两个按钮永远按 1:1 平分宽度,与屏幕宽窄无关。实战里通常组合使用:手机用一份默认布局,平板用限定符目录里的双栏布局。

⚠️ 常见坑三连:

  • 字号写成 dp:用户调大系统字体后你的 App 无动于衷,视障用户体验直线下降;
  • 用 px 硬写:换台手机控件大小错乱,代码评审一眼打回;
  • 在代码里 setTextColor 之类传 px 参数:有些 API 收的就是 px,需要按密度手动换算,直接把 dp 数值丢进去会小得看不见。

本节要点回顾

  • dpi 是密度不是分辨率:像素数相同,物理大小可以天差地别。
  • 换算公式:px = dp × dpi ÷ 160,xxhdpi 下 1dp = 3px。
  • sp 与 dp 唯一区别:sp 跟随系统字体缩放,字号必须用 sp。
  • 触摸目标 ≥ 48dp:这是可点击控件的可用性底线。
  • 宽度限定符:平板等大屏给独立布局目录,配合 weight 比例分配适配大小屏。

适配问题的排查路径

实际项目里适配问题五花八门,但排查有固定套路可循。第一步永远问:这个尺寸写的是什么单位?ImageView 高度写死 dp 在大屏上偏小、文字用 dp 导致老年用户放大字体的需求失效,八成适配 bug 的病根都在单位错配上。第二步问:这个控件的尺寸来自哪里?match_parent、wrap_content、固定值、权重、约束各自有不同的失效场景,比如 wrap_content 遇到长文案就会在窄屏上溢出。第三步才轮到工具:模拟器开三个分辨率档各跑一遍,横竖屏各看一次,深色模式顺带扫一眼。三步走完还定位不了的,用布局检查器看真实测量值,第 8 章的标准流程在此候命。顺带建立一个数量级感觉:主流手机的密度桶大致在 hdpi 到 xxxhdpi 之间,一倍 dp 对应的物理像素从 1.5 到 4 不等——理解了这个倍率区间,"为什么同一个 dp 在不同手机上看起来差不多大"就不再是魔法。

再补一个新手几乎必踩的换算细节: dimens 里存的永远是 dp 或 sp 数值,换算发生在渲染时,也就是说你无法在代码里直接"读出"某个 dp 对应多少像素——需要换算时用 resources.displayMetrics 里的 density 因子乘出来,触摸手势的像素阈值(第 5 章的滑动判定)就是这种场景。理解"单位属于声明、换算属于系统"这条分工,单位混乱的问题就断了根。至于平板与折叠屏这类大屏适配,手段仍是同一套:约束、权重、限定词三件套换参数不换思想,等你的 App 真要上平板时,本章的底子直接够用。

一个日常协作细节作为本节的句号:和设计师对稿时养成报 dp 而不报 px 的习惯——设计稿标注 24px 在一倍图与三倍图上含义不同,统一换算成 dp 再沟通,可以消灭大半"尺寸对不上"的无效来回,也让单位纪律从个人习惯升级为团队协议。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U