1. 基础概念
1.1. px(物理像素,pixel)
屏幕上一个最小的点,用来显示颜色和图像。
- 举例:一个屏幕宽度是 1080px,意思是水平方向上有 1080 个小点。
- 一个单位的实际大小取决于屏幕密度(ppi/dpi):
1.2. 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 越大,同样的图形看起来就越小越精细。
1.2.1. 开发时如何查看设备DPI
使用如下adb命令:
adb shell wm density
1.3. ppi(pixels per inch,每英寸像素数)
屏幕像素密度,和 dpi 类似,都表示“每英寸像素数”,但 PPI 更常用于描述物理屏幕。"。
- iPhone 或安卓手机介绍里常见,比如 “iPhone 13 是 460 ppi”。
📌 区别:
- DPI 通常用于衡量打印清晰度
- PPI 通常用于衡量屏幕清晰度
- 两者计算方式相同但应用领域不同
虽然从技术严谨性上讲,屏幕应该用 PPI 来描述像素密度,但 Android 平台选择使用 DPI 作为其屏幕密度分类的命名,更多是出于历史习惯、方便开发者理解和适配、以及内部系统将设备归类到标准密度的实用性考量。在实际开发中,当你看到 Android 相关的“DPI”时,把它理解为“像素密度”或“屏幕的 PPI”是完全正确的。
1.4. 分辨率(resolution)
分辨率指的是屏幕水平方向和垂直方向的像素数量。
常见格式是:宽 × 高(px)
📌 举例:
- 1920×1080(1080p):表示屏幕宽有 1920 个像素,高有 1080 个像素。
- 1280×800:宽是 1280 像素,高是 800 像素。
- 2400×1080:是很多安卓手机的常见分辨率。
1.4.1. 分辨率与清晰度的基础关系
理论上来讲像素点越多,图像细节越丰富、边缘越平滑。
在相同屏幕尺寸下,更高的分辨率意味着更多像素点填充画面,能呈现更细腻的纹理和更少的锯齿感。
1.4.2. ****分辨率常见误区:
- 分辨率是不是越大显示越细腻?
这个说法并不完全准确,还要加一个限定词,同样尺寸的设备,分辨越大,显示越细腻,其实就是指的ppi。
- 分辨率是不是越大越好?
不是,如果屏幕很小,但是分辨率特别高,会导致文字和图标过小,看不清楚,一般来讲,厂家会根据屏幕尺寸给出测算出观看距离,设定合适的分辨率。
视网膜屏(Retina):乔布斯在2010年iPhone 4发布会上提出:当屏幕像素密度≥300 PPI(每英寸像素数),且观看距离约25-30厘米时,肉眼无法分辨像素点
1.4.3. 开发时如何查看设备分辨率
使用如下adb命令:
adb shell wm size
1.4.4. 常说的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 | 超高清电视、专业拍摄 |
💡 注意几点细节:
- 4K 不是 1080p 的四倍(而是指宽度约为 1K 像素的四倍);
- “K” 是一个命名惯例,不是严格标准,常常是市场化说法。
1.5. dp(密度无关像素,density-independent pixel)
Android 专用单位,是一种逻辑像素,用于适配不同屏幕密度。
- 它让你的布局在不同设备上看起来差不多大,这里的大小指的是视觉上的大小,即物理上的。
- 1dp 大约等于在 160 dpi 屏幕上 1px,就是说一个160dpi的屏幕,1dp=1px,如果是320dpi的屏幕,1dp=2px。公式: px = dp × (当前DPI/160)
为什么是160:160是Android的基准密度(mdpi),源于早期设备的典型参数,以160为基准,可避免当时常用的dpi在计算时产生浮点运算(如120dpi比例=0.75,240dpi比例=1.5)。
这里大家直接记住就好了,就好像1cm=10mm一样,为什么是10,就是方便计算。
📌 举例:你写了一个按钮宽度是 100dp
- 在低分辨率屏幕上,它可能是 100px 宽
- 在高分辨率屏幕上,可能是 200px 宽(但看起来还是差不多大)
1.5.1. 其他设备的逻辑像素
对应android用的dp,苹果上的单位是pt,web端使用px,这些都是逻辑像素单位,有不一样的换算关系。尤其注意web端里面开发用到的px和上面介绍的px是不一样的,虽然缩写一样,但web端开发用的是CSS像素,上面介绍的是物理像素。
换算关系:
- 苹果:在
@1x设备下,1pt=1px。 - web:在 DPR(devicePixelRatio)=1 的设备上,1px(css像素)=1px(物理像素)。
1.6. 一句话总结
- PX:屏幕上的「点」,物理像素,其物理大小会随设备密度变化。
- DPI/PPI:描述「点有多密」
- 分辨率: 屏幕上所有像素点的总数
- DP:Android的「虚拟厘米」,是一种逻辑像素,保证显示一致
2. android如何适配不同屏幕
2.1. 设计稿与开发的关系
这里说一下常见的UI设计软件 Figma,它在开发模式下取的值是逻辑像素,也就是dp。这里dp和px的转换关系都基于160dpi的情况,即1dp=1px。Figma目前也不支持配置dpi。其它设备,如ios和web也同理,按一倍关系进行转换。
2.2. 如何解决不同屏幕适配问题
在基础概念上提到的dp,使得元素在不同设备的物理大小看起来是基本一致的。
但是这并不能彻底解决问题。例如下图,如果设计稿中的元素宽度进行设置,不同屏幕尺寸的显示虽然元素大小一致,但是由于屏幕的物理大小不一致,所以显示还是会有异常。
上图的示意代码编写方式是按设计稿的固定尺寸设置的,如果按照等分的方式设置(如下图),那么这个问题就不存在了,因为这里是系统在布局的时候自动计算出来的宽度。
那么有没有一种方式,在我编写代码的时候写固定尺寸,在其他不同设备显示时,也能实现类似等分的效果。
答案是肯定的,只需将这个元素按照屏幕的实际尺寸,和基准设备的尺寸做对比后,进行缩放就好了。
那么这个计算的过程是放在哪里做的呢,当然不是每次都手动计算,有自动化的工具可以自动生成。说这个工具之前先补充一下知识点:android尺寸资源文件和资源限定符。
2.3. android尺寸资源文件
在 Android 开发中,dimens 是一个非常重要的资源类型,它用于定义尺寸值。这些尺寸值包括长度、高度、宽度、边距、填充、文本大小等,它们通常以 DP(密度无关像素) 或 SP(可伸缩像素) 为单位。
默认的尺寸资源文件在res/values/dimens.xml。
示例dimens.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>
如何在布局文件中使用:
<!-- 没使用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" />
这实际上就是把硬编码的地方改为引用变量的方式,为我们做屏幕适配打下良好的基础。
2.4. 资源限定符
dimens.xml结合 资源限定符 (Resource Qualifiers) ,你可以为不同屏幕尺寸、不同像素密度、不同横竖屏模式等设备提供不同的尺寸值。
示例:
res/values/dimens.xml:
<dimen name="detail_image_height">200dp</dimen>
res/values-sw600dp/dimens.xml (针对 7 英寸及以上平板):
<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。
这里的资源限定符是最小宽度,还有别的资源限定符,如高度、宽度等等。
2.4.1. 如何创建values-swdp文件
目录视图模式切换为Android:
选择dimens文件夹→鼠标右键→选择New→选择Values Resource File:
找到最小宽度资源限定符→点击>>符号:
填写固定的文件名称dimens.xml→填写指定的最小宽度,这里假设为600→点击OK按钮:
将视图切换到Project,会发现在res文件夹下面自动创建了一个名称为values-sw600dp的文件夹,并且里面有一个新的dimens.xml文件:
2.5. 自动化适配插件ScreenMatch
自己一个一个文件夹创建太麻烦了,而且也不知道对应关系,更不知道里面具体变量的值要填什么。这里推荐一个插件叫ScreenMatch。
2.5.1. 安装
打开Settings→在Marketplace中搜索ScreenMatch→点击INSTALL按钮:
2.5.2. 使用
使用方式很简单:在项目目录中,在任意文件或文件夹上右键点击鼠标→选择ScreenMatch→点击ScreenMatch:
选择对应的模块→点击OK按钮:
然后就会自动生成对应的dimens、一个配置文件screenMatch.properties和一个示例dimens文件:
2.5.3. 配置说明
screenMatch.properties文件:
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文件中。
2.5.4. 常见问题
2.5.4.1. screenMatch适用范围
一般来讲,我们说的多尺寸适配,就是出一份设计稿,开发一次,在不同尺寸的设备都有良好的视觉体验,然而,这种方法主要适用于尺寸和宽高比相近的设备。ScreenMatch的原理是根据设备的DPI和分辨率,对不同宽度的设备进行等比缩放。如果设备尺寸与UI设计稿的差异过大,则难以提供良好的视觉体验,因此这种适配方式并非万能。
比如一样的文本和图片,在很小的设备上,强行压缩会看不清。同样,给手机设计的UI稿,放大后放在平板上,元素也会变得很大,浪费空间。
真的差异大的设备,还是需要出多份设计稿,至少手机、平板、横竖屏都得分别设计。
2.5.4.2. 使用screenMatch,如何计算当前设备匹配了哪个dimens.xml
公式: sw/(dpi/160),结果是多少,就匹配的是哪个。
例子: 如果设备的分辨率是1280x800px,dpi是320,结果为800/(320/160)=400,也就是说会匹配values-sw400dp下的dimens.xml。
2.5.4.3. 为什么使用sw而不用w作为资源限定符
sw指的是最小宽度,而w指的就是宽度。假如,设备分辨率是1080 x 1920px,dpi是320,那么sw就是1080/(320/160)=540,不管是横屏还是竖屏,都是540dp;
而如果取w作为资源限定符,竖屏的时候和sw一样是540dp,横屏的时候就变成1920/(320/160)=960了,也就是说取w的时候切换横竖屏,缩放比例是不一样的。
还有一点,用w是很难确定当前尺寸是一个什么类型的设备,例如手机的横屏可能比中型平板的竖屏宽度要大,那这个设备是手机还是平板就很难区分,用哪套设计稿也很难判断,sw就不会,宽度就固定是短的那个,可以用来区分手机、中型尺寸平板,大型尺寸平板等。
如果有特殊需求,可以通过设置screenMatch.properties文件里面的create_values_sw_folder属性做到。
2.5.4.4. 为什么基于宽度做适配,而不是高度
因为一般的交互都是竖向滚动,横向的很少。只要横向适配好了,高度溢出的部分用ScrollView处理就好了。
2.5.4.5. 使用默认的base_dp配置显示异常
如果说你想要适配平板等更大尺寸的设备,需要修改一下base_dp,原来默认的360是手机的尺寸。
常见尺寸:
360: 主流尺寸手机600:7寸平板720、820:10寸平板
2.5.5. 使用ScreenMatch的开发设计流程
- 设计师依据目标设备定基准尺寸:
-
- 如果是手机的设计稿:使用360宽度的设备作为基准设备进行UI设计
- 如果UI平板:依据主流平板的宽度作为基准进行UI设计
- 如果是特定设备:直接取特定设备的宽度(px)为基准进行UI设计
- 开发人员配置ScreenMatch:
-
- 先运行
ScreenMatch生成默认配置 - 依据需要,修改
base_dp填入设计师UI稿的宽度(注意,这里是最小宽度,即横竖屏中较短的那条边)。 - 重新运行
ScreenMatch,更新配置
- 先运行
- 开发人员进行开发验证:
-
- 找一个简单的页面,按设计师出的UI做出对应的布局文件,里面的尺寸全部用
dimens变量进行设置。
- 找一个简单的页面,按设计师出的UI做出对应的布局文件,里面的尺寸全部用
- 开发人员选择对应尺寸的设备或新建对应尺寸的设备,验证这个页面的显示效果是否与UI一致:
-
- 如何切换预览设备尺寸:
-
- 如何新建尺寸:
拉到最下面,点击Add Device Definition:
点击New hardware profile:
分辨率改成和你要测试目标设备的分辨率一致,点击FINISH就可以使用了:
2.5.6. 总结
ScreenMatch在你写固定尺寸值的时候,在大小差不多的设备做适配,原理是通过资源限定符和字符串资源文件,实现动态引用,其缩放值由当前设备像素,像素密度与基准设备(UI稿)的比例共同决定。
2.6. 自动化适配库AndroidAutoSize
这是一个今日头条屏幕适配方案,与插件不一样,是通过引入第三方库的方式实现的屏幕适配,库的地址放在参考连接里了。
2.6.1. 如何使用
官方有详细的使用说明,这里简单说一下:
2.6.1.1. 安装
在项目根目录的build.gradle加入jitpack仓库地址:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
在app级build.gradle加入依赖
dependencies {
implementation 'com.github.JessYanCoding:AndroidAutoSize:v1.2.1'
}
2.6.1.2. 配置
在AndroidManifest中填写设计稿的尺寸:
<manifest>
<application>
<meta-data
android:name="design_width_in_dp"
android:value="360"/>
<meta-data
android:name="design_height_in_dp"
android:value="640"/>
</application>
</manifest>
注意:这里官方没提,经验证,使用的是设计稿的宽度,不是最小宽度,要注意选横向的那个长度,填错了适配会有问题。
2.6.1.3. 基本原理
动态修改 Android 系统的 DisplayMetrics 密度值,让系统按照我们期望的比例计算 dp、sp 等单位的实际像素大小。
DisplayMetrics 的常用字段:
| 属性 | 含义 |
|---|---|
| widthPixels | 屏幕宽度(像素) |
| heightPixels | 屏幕高度(像素) |
| density | 逻辑密度值,相当于 dp 与 px 的比例(如 1.0 / 2.0) |
| densityDpi | 每英寸像素数(DPI),如 mdpi=160,hdpi=240 等 |
| scaledDensity | 字体缩放比例,根据用户字号设置自动调整 |
| xdpi & ydpi | 屏幕 X/Y 方向的真实物理像素密度 |
适配原理与ScreenMatch的区别:
ScreenMatch:按特定dpi生成缩放后的变量供开发时候引用AndroidAutoSize:在运行时修改缩放比例进行页面适配
2.7. ScreenMatch与AndroidAutoSize的优缺点
ScreenMatch:
-
优点
- 直接预览布局:可以在 Android Studio 中方便创建虚拟预览设备(以 dp、pt、in、mm 为单位),快速预览各种屏幕尺寸下的布局效果 。
- 运行时无额外开销:仅在设计阶段生成适配资源,运行时不做动态计算,对性能无影响 。
-
缺点
- 依赖资源文件定义:如果项目之前大量使用硬编码 dp 值,则必须统一替换为 dimens 并维护多套资源文件,工作量较大。
- 适配新尺寸需重新生成资源并打包:每次支持新设备,都需要重新生成相应 dimens 和资源包。
AndroidAutoSize:
-
优点
- 侵入性小:无需改动现有 dp/sp 布局,几乎不用修改原始硬编码布局 。
- 支持运行时动态调整:通过修改 DisplayMetrics(density、scaledDensity、densityDpi),实现运行时根据不同屏幕尺寸按比例缩放,适配新设备无需重新打包 。
- 安装配置简单:通过 AndroidManifest 中配置 design_width_in_dp 即可使用,支持按宽或按高适配,灵活方便 。
-
缺点
- 兼容风险:AndroidAutoSize 会修改 Application 和 Activity 的 DisplayMetrics,这可能影响依赖原始 density 的第三方库或系统组件(如 WebView、地图 SDK),如果遇到厂商系统对 density 做了特别处理,有可能出现显示异常 。
- 开发预览不方便:实时 preview 因为依赖系统默认 density,而库运行时修改了 DisplayMetrics,因此在 IDE 预览时可能无法正确反映最终效果,需要开发者自行新建虚拟设备(虚拟宽度/高度)以 dp 为单位去预览。
2.8. 总结
自动适配可以通过ScreenMatch或AndroidAutoSize实现,但本质都是通过一定的计算方式,前置或后置的对元素进行缩放,以在相近尺寸、不同dpi屏幕上有一样的视觉体验。