一文读懂 Android 屏幕适配:从基础到实践

基础概念

px(物理像素,pixel)

屏幕上一个最小的点,用来显示颜色和图像。

  • 举例:一个屏幕宽度是 1080px,意思是水平方向上有 1080 个小点。
  • 一个单位的实际大小取决于屏幕密度(ppi/dpi):

dpi(dots per inch,每英寸点数)

屏幕密度,意思是每英寸有多少个墨点。

  • 主要用于打印机和扫描仪: DPI 最初用来描述打印机每英寸能打印多少个墨点,以及扫描仪每英寸能捕捉多少个点。
  • 次要用于屏幕(有时与PPI互换): 虽然严格来说屏幕是用像素而不是墨点,但在某些语境下(尤其是在早期的Windows系统中),DPI 也被用来指代屏幕的像素密度,与 PPI 类似。
  • 关系: 在打印领域,DPI 越高,打印出来的图像就越精细。在数字图像处理中,DPI/PPI 决定了图像在显示或打印时的物理尺寸和清晰度。
  • android常见的密度级别 (Density Buckets)
    • 160 dpi:标准密度(mdpi)
    • 320 dpi:高密度(xhdpi)
    • 480 dpi:超高密度(xxhdpi)
    • dpi 越大,同样的图形看起来就越小越精细。

开发时如何查看设备DPI

使用如下adb命令:

bash 复制代码
adb shell wm size

ppi(pixels per inch,每英寸像素数)

屏幕像素密度 ,和 dpi 类似,都表示"每英寸像素数",但 **PPI **更常用于描述物理屏幕。"。

  • iPhone 或安卓手机介绍里常见,比如 "iPhone 13 是 460 ppi"。

📌 区别:

  • DPI 通常用于衡量打印清晰度
  • PPI 通常用于衡量屏幕清晰度
  • 两者计算方式相同但应用领域不同

虽然从技术严谨性上讲,屏幕应该用 PPI 来描述像素密度,但 Android 平台选择使用 DPI 作为其屏幕密度分类的命名,更多是出于历史习惯、方便开发者理解和适配、以及内部系统将设备归类到标准密度的实用性考量。在实际开发中,当你看到 Android 相关的"DPI"时,把它理解为"像素密度"或"屏幕的 PPI"是完全正确的。

分辨率(resolution)

分辨率指的是屏幕水平方向和垂直方向的像素数量

常见格式是:宽 × 高(px)

📌** 举例:**

  • 1920×1080(1080p):表示屏幕宽有 1920 个像素,高有 1080 个像素。
  • 1280×800:宽是 1280 像素,高是 800 像素。
  • 2400×1080:是很多安卓手机的常见分辨率。

分辨率**与清晰度的基础关系**

理论上来讲像素点越多,图像细节越丰富、边缘越平滑。

在相同屏幕尺寸下,更高的分辨率意味着更多像素点填充画面,能呈现更细腻的纹理和更少的锯齿感。

****分辨率常见误区:

  1. 分辨率是不是越大显示越细腻?

这个说法并不完全准确,还要加一个限定词,同样尺寸的设备,分辨越大,显示越细腻,其实就是指的ppi。

  1. 分辨率是不是越大越好?

不是,如果屏幕很小,但是分辨率特别高,会导致文字和图标过小,看不清楚,一般来讲,厂家会根据屏幕尺寸给出测算出观看距离,设定合适的分辨率。

视网膜屏(Retina):乔布斯在2010年iPhone 4发布会上提出:当屏幕像素密度≥300 PPI(每英寸像素数),且观看距离约25-30厘米时,肉眼无法分辨像素点

开发时如何查看设备分辨率

使用如下adb命令:

bash 复制代码
adb shell wm size

常说的2k屏、4k屏是什么

"K" 是 kilo 的缩写,代表"约一千像素"。

它指的是横向(宽度)像素的数量 ,但只是个近似命名,不是精准的技术指标。

常见 K 分辨率标准对照表
名称 分辨率(宽×高) 实际宽度 px 应用场景
1K(HD) 1280×720 ≈ 1,000 px 手机、入门级视频
2K(Full HD) 1920×1080 ≈ 2,000 px 电视、主流显示器
2K(影院标准) 2048×1080 2048 px 数字电影放映
4K(UHD) 3840×2160 ≈ 4,000 px 高清电视、4K显示器
4K(影院标准) 4096×2160 4096 px 数字电影制作
8K(UHD) 7680×4320 ≈ 8,000 px 超高清电视、专业拍摄

💡** 注意几点细节:**

  1. 4K 不是 1080p 的四倍(而是指宽度约为 1K 像素的四倍);
  2. "K" 是一个命名惯例,不是严格标准,常常是市场化说法。

dp(密度无关像素,density-independent pixel)

Android 专用单位,是一种逻辑像素,用于适配不同屏幕密度。

  • 它让你的布局在不同设备上看起来差不多大,这里的大小指的是视觉上的大小,即物理上的。
  • 1dp 大约等于在 160 dpi 屏幕上 1px,就是说一个160dpi的屏幕,1dp=1px,如果是320dpi的屏幕,1dp=2px。**公式:**px = dp × (当前DPI/160)

为什么是160:160Android的基准密度 (mdpi),源于早期设备的典型参数,以160为基准,可避免当时常用的dpi在计算时产生浮点运算(如120dpi比例=0.75,240dpi比例=1.5)。

这里大家直接记住就好了,就好像1cm=10mm一样,为什么是10,就是方便计算。

📌 举例:你写了一个按钮宽度是 100dp

  • 在低分辨率屏幕上,它可能是 100px 宽
  • 在高分辨率屏幕上,可能是 200px 宽(但看起来还是差不多大)

其他设备的逻辑像素

对应android用的dp,苹果上的单位是pt,web端使用px,这些都是逻辑像素单位,有不一样的换算关系。尤其注意web端里面开发用到的px和上面介绍的px是不一样的,虽然缩写一样,但web端开发用的是CSS像素,上面介绍的是物理像素。

换算关系

  • 苹果:在@1x设备下,1pt=1px。
  • web:在 DPR(devicePixelRatio)=1 的设备上,1px(css像素)=1px(物理像素)。

一句话总结

  • PX:屏幕上的「点」,物理像素,其物理大小会随设备密度变化。
  • DPI/PPI:描述「点有多密」
  • **分辨率:**屏幕上所有像素点的总数
  • DP:Android的「虚拟厘米」,是一种逻辑像素,保证显示一致

android如何适配不同屏幕

设计稿与开发的关系

这里说一下常见的UI设计软件 Figma,它在开发模式下取的值是逻辑像素,也就是dp。这里dp和px的转换关系都基于160dpi的情况,即1dp=1px。Figma目前也不支持配置dpi。其它设备,如ios和web也同理,按一倍关系进行转换。

如何解决不同屏幕适配问题

在基础概念上提到的dp,使得元素在不同设备的物理大小看起来是基本一致的。

但是这并不能彻底解决问题。例如下图,如果设计稿中的元素宽度进行设置,不同屏幕尺寸的显示虽然元素大小一致,但是由于屏幕的物理大小不一致,所以显示还是会有异常。

上图的示意代码编写方式是按设计稿的固定尺寸设置的,如果按照等分的方式设置(如下图),那么这个问题就不存在了,因为这里是系统在布局的时候自动计算出来的宽度。

那么有没有一种方式,在我编写代码的时候写固定尺寸,在其他不同设备显示时,也能实现类似等分的效果。

答案是肯定的,只需将这个元素按照屏幕的实际尺寸,和基准设备的尺寸做对比后,进行缩放就好了。

那么这个计算的过程是放在哪里做的呢,当然不是每次都手动计算,有自动化的工具可以自动生成。说这个工具之前先补充一下知识点:android尺寸资源文件和资源限定符。

android尺寸资源文件

在 Android 开发中,dimens 是一个非常重要的资源类型,它用于定义尺寸值。这些尺寸值包括长度、高度、宽度、边距、填充、文本大小等,它们通常以 **DP(密度无关像素)**或 **SP(可伸缩像素)**为单位。

默认的尺寸资源文件在res/values/dimens.xml

示例 **dimens.xml**文件

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="spacing_small">8dp</dimen>
    <dimen name="spacing_medium">16dp</dimen>
    <dimen name="spacing_large">24dp</dimen>

    <dimen name="button_height">48dp</dimen>
    <dimen name="button_corner_radius">4dp</dimen>

    <dimen name="text_size_body">16sp</dimen>
    <dimen name="text_size_headline">24sp</dimen>

    <dimen name="avatar_size">56dp</dimen>
    <dimen name="card_elevation">2dp</dimen>
</resources>

如何在布局文件中使用:

xml 复制代码
<!-- 没使用dimens -->
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="16sp"
    android:padding="16dp"
    android:layout_marginTop="24dp"
    android:text="Hello World" />

<!-- 使用dimens -->
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="@dimen/text_size_body"
    android:padding="@dimen/spacing_medium"
    android:layout_marginTop="@dimen/spacing_large"
    android:text="Hello World" />

这实际上就是把硬编码的地方改为引用变量的方式,为我们做屏幕适配打下良好的基础。

资源限定符

**dimens.xml**结合 资源限定符 (Resource Qualifiers),你可以为不同屏幕尺寸、不同像素密度、不同横竖屏模式等设备提供不同的尺寸值。

示例:

res/values/dimens.xml

plain 复制代码
<dimen name="detail_image_height">200dp</dimen>

res/values-sw600dp/dimens.xml (针对 7 英寸及以上平板):

plain 复制代码
<dimen name="detail_image_height">300dp</dimen>

手机在运行时会识别出当前设备的最小宽度(或其它限定符),然后将对应宽度的资源应用在UI上。

同一个 detail_image_height 在手机上是 200dp,而在平板上就是 300dp,从而更好地利用屏幕空间,提供更优的视觉效果。

这里values-sw600dp的意思是:如果设备的最小宽度(Smallest Screen Width,sw大于或等于 600dp,系统将使用values-sw600dp文件夹下的dimens.xml否则 ,将使用默认的values文件夹下的dimens.xml

这里的资源限定符是最小宽度,还有别的资源限定符,如高度、宽度等等。

如何创建values-swdp文件

目录视图模式切换为Android

选择dimens文件夹→鼠标右键→选择New→选择Values Resource File

找到最小宽度资源限定符→点击>>符号:

填写固定的文件名称dimens.xml→填写指定的最小宽度,这里假设为600→点击OK按钮:

将视图切换到Project,会发现在res文件夹下面自动创建了一个名称为values-sw600dp的文件夹,并且里面有一个新的dimens.xml文件:

自动化适配插件ScreenMatch

自己一个一个文件夹创建太麻烦了,而且也不知道对应关系,更不知道里面具体变量的值要填什么。这里推荐一个插件叫ScreenMatch

安装

打开Settings→在Marketplace中搜索ScreenMatch→点击INSTALL按钮:

使用

使用方式很简单:在项目目录中,在任意文件或文件夹上右键点击鼠标→选择ScreenMatch→点击ScreenMatch:

选择对应的模块→点击OK按钮:

然后就会自动生成对应的dimens、一个配置文件screenMatch.properties�和一个示例dimens文件:

配置说明

**screenMatch.properties�**文件:

xml 复制代码
base_dp=360
match_dp=1300
ignore_dp=240
  • base_dp:就是把UI分成多少份,360就是分成360份,为啥取360,因为主流的手机尺寸都是360的倍数,能够整除,值为360可以覆盖90%的手机机型。如果要修改,建议改为和你设计稿的最小宽度一样的值,这样默认的变量和值就是1:1,方便开发。
  • match_dp:在插件运行时,默认会生成多个dimens文件。如果默认生成的dimens文件中不包含你希望适配的屏幕尺寸,你可以在此处添加。例如,上述配置会额外生成1300dp宽度的dimens文件。
  • ignore_dp:不生成对应的尺寸的dimens,例子中是取消生成240dp下的dimens

**screenMatch_example_dimens.xml**文件:

  • 这是一个默认dimens的示例文件,仅供参考,不会在实际应用中被直接使用。如果需要,你可以将其内容复制到默认的dimens.xml文件中。

常见问题

screenMatch适用范围

一般来讲,我们说的多尺寸适配,就是出一份设计稿,开发一次,在不同尺寸的设备都有良好的视觉体验,然而,这种方法主要适用于尺寸和宽高比相近的设备。ScreenMatch的原理是根据设备的DPI和分辨率,对不同宽度的设备进行等比缩放。如果设备尺寸与UI设计稿的差异过大,则难以提供良好的视觉体验,因此这种适配方式并非万能。

比如一样的文本和图片,在很小的设备上,强行压缩会看不清。同样,给手机设计的UI稿,放大后放在平板上,元素也会变得很大,浪费空间。

真的差异大的设备,还是需要出多份设计稿,至少手机、平板、横竖屏都得分别设计。

使用screenMatch,如何计算当前设备匹配了哪个 **dimens.xml**

公式: sw/(dpi/160),结果是多少,就匹配的是哪个。

**例子:**如果设备的分辨率是1280x800,dpi是320,结果为800/(320/160)=400,也就是说会匹配values-sw400dp下的dimens.xml

为什么使用sw而不用w作为资源限定符

sw指的是最小宽度,而w指的就是宽度。假如,设备分辨率是1080 x 1920,dpi是320,那么sw就是1080/(320/160)=540,不管是横屏还是竖屏,都是540dp;

而如果取w作为资源限定符,竖屏的时候和sw一样是540dp,横屏的时候就变成1920/(320/160)=960了,也就是说取w的时候切换横竖屏,缩放比例是不一样的。

还有一点,用w是很难确定当前尺寸是一个什么类型的设备,例如手机的横屏可能比中型平板的竖屏宽度要大,那这个设备是手机还是平板就很难区分,用哪套设计稿也很难判断,sw就不会,宽度就固定是短的那个,可以用来区分手机、中型尺寸平板,大型尺寸平板等。

如果有特殊需求,可以通过设置screenMatch.properties�文件里面的create_values_sw_folder属性做到。

为什么基于宽度做适配,而不是高度

因为一般的交互都是竖向滚动,横向的很少。只要横向适配好了,高度溢出的部分用ScrollView处理就好了。

使用默认的base_dp配置显示异常

如果说你想要适配平板等更大尺寸的设备,需要修改一下base_dp,原来默认的360是手机的尺寸。

常见尺寸:

  • 360: 主流尺寸手机
  • 600:7寸平板
  • 720、820:10寸平板

使用ScreenMatch的开发设计流程

  • 设计师 依据目标设备定基准尺寸:
    • 如果是手机的设计稿:使用360宽度的设备作为基准设备进行UI设计
    • 如果UI平板:依据主流平板的宽度作为基准进行UI设计
    • 如果是特定设备:直接取特定设备的宽度(px)为基准进行UI设计
  • 开发人员 配置ScreenMatch:
    1. 先运行ScreenMatch生成默认配置
    2. 依据需要,修改base_dp填入设计师UI稿的宽度(注意,这里是最小宽度,即横竖屏中较短的那条边)。
    3. 重新运行ScreenMatch,更新配置
  • 开发人员 进行开发验证:
    • 找一个简单的页面,按设计师出的UI做出对应的布局文件,里面的尺寸全部用dimens变量进行设置。
  • 开发人员 选择对应尺寸的设备或新建对应尺寸的设备,验证这个页面的显示效果是否与UI一致:
    • 如何切换预览设备尺寸:
diff 复制代码
- 如何新建尺寸:

拉到最下面,点击Add Device Definition

点击New hardware profile

分辨率改成和你要测试目标设备的分辨率一致,点击FINISH就可以使用了:

参考

相关推荐
Xf3n1an1 小时前
html语法
前端·html
张拭心1 小时前
亚马逊 AI IDE Kiro “狙击”Cursor?实测心得
前端·ai编程
烛阴1 小时前
为什么你的Python项目总是混乱?层级包构建全解析
前端·python
CYRUS_STUDIO1 小时前
深入 Android syscall 实现:内联汇编系统调用 + NDK 汇编构建
android·操作系统·汇编语言
@大迁世界2 小时前
React 及其生态新闻 — 2025年6月
前端·javascript·react.js·前端框架·ecmascript
红尘散仙3 小时前
Rust 终端 UI 开发新玩法:用 Ratatui Kit 轻松打造高颜值 CLI
前端·后端·rust
死也不注释3 小时前
【第一章编辑器开发基础第一节绘制编辑器元素_6滑动条控件(6/7)】
android·编辑器
新酱爱学习3 小时前
前端海报生成的几种方式:从 Canvas 到 Skyline
前端·javascript·微信小程序
袁煦丞3 小时前
把纸堆变数据流!Paperless-ngx让文件管理像打游戏一样爽:cpolar内网穿透实验室第539个成功挑战
前端·程序员·远程工作
慧慧吖@3 小时前
关于两种网络攻击方式XSS和CSRF
前端·xss·csrf