-
Notifications
You must be signed in to change notification settings - Fork 128
屏幕适配
dpi = √(宽² + 高²) / 屏幕尺寸
density表示1dp有多少像素,它的计算公式如下:
density = dpi / 160;
Android早期将160dpi作为“中等密度”的基准,这一数值的选择源于早期主流设备的实际像素密度(如HTC G1的160dpi),同时通过整除关系简化计算:
120dpi(低密度)= 160/1.33
240dpi(高密度)= 160×1.5
320dpi(超高密度)= 160×2 。 以160dpi为基准时,1dp在标准屏幕上等于1px,高于或低于基准密度的屏幕则按比例缩放,确保UI元素在不同设备上显示大小一致
根据density的含义可以得出px的计算方式:
px = dp * density;
density-independent pixel,是 Android 特有的单位,只与 DPI 有关,保证了在不同屏幕像素密度的设备上显示相同的效果。以 DPI=160 为基准 1dp=1px,用设备实际DPI值/160=density 密度,即 1dp 等于多少 px。用屏幕宽或高的 px/density= 屏幕宽或高最大dp长度。
市面上的机型,不同分辨率*不同屏幕尺寸=无限多种DPI组合。
举个例子
- 一个5英寸的手机,分辨率为1080*1920,根据公式计算出dpi为440,density为2.75,因此这款手机的宽度为1080/2.75=392.73dp
- 一个5英寸的手机,分辨率为1280*720 ,根据公式计算出dpi为293,density为4.3 ,因此这款手机的宽度为1280/4.3 = 297dp
因此,如果在第二款手机上设置宽度为 297dp,刚好充满屏幕。而如果在第一款手机上则无法充满屏幕。因此可以看出 dp 并不能适配所有屏幕。
通过穷举市面上所有 Android 手机的屏幕像素尺寸来实现适配,通过比例换算来为不同分辨率的屏幕分别准备一套 dimens 文件,应用在运行时再去引用和当前设备完全匹配的 dimens 文件,以此来实现屏幕适配。
这一方案最大的确定是容错率低,只有精准匹配分辨率才能适配,否则只能引用默认dimens文件夹,显示效果就会有很大出入。


大部分手机的宽度 dp 值集中在 320-450 之间,大部分 1080P 的手机应该都是 360dp,390dp,411dp。smallestWidth 限定符适配需要在 res 文件夹下创建各种屏幕分辨率对应的 values-swxxxdp 文件夹,如下图:

smallestWidth 限定符适配原理与屏幕分辨率限定符适配原理一样,系统都是根据限定符去寻找对应的 dimens.xml 文件。例如程序运行在最小宽度为 360dp 的设备上,系统会自动找到对应的 values-sw360dp 文件夹下的 dimens.xml 文件。如果没有匹配当刚好一样大小的分辨率,则选择相差最小的文件夹下的 dimens.xml。需要注意的是“最小宽度”是不区分方向的,即无论是宽度还是高度,哪一边小就认为哪一边是“最小宽度”。
根据设计师给的设计稿的宽高计算出屏幕的dp宽度,比如,经计算,设计师给的设计稿的宽度为 375dp 。那么就以 values-sw375dp 为基准,那么就在该目录下添加 dp 值。如下:
<dimen name="dp_1">1dp</dimen>
<dimen name="dp_1_5">1.5dp</dimen>
<dimen name="dp_2">2dp</dimen>
<dimen name="dp_2_5">2.5dp</dimen>
<dimen name="dp_3">3dp</dimen>
<dimen name="dp_4">4dp</dimen>
<dimen name="dp_4_5">4.50dp</dimen>
<dimen name="dp_5">5dp</dimen>
<dimen name="dp_6">6dp</dimen>
...
其它 values 目录则只需根据与 375dp 的比值扩大或者缩小dp值即可。例如,values-sw750dp 下 dp_1 的值应该刚好为 values-sw375dp目录下值的2倍。
当然,这么多文件不需要自己编写。可以通过 As 插件自动生成即可。插件地址: ScreenMatch
今日头条适配方案默认项目中只能以宽作为基准,进行适配。我们根据density的计算公式,以设计稿的宽度作为标准,可得出如下公式:
设计图总宽度(单位为 dp) = 当前设备屏幕总宽度(单位为像素)/ density
上述公式中因为设计稿的宽度是不变的,当前设备屏幕总宽度也是无法改变的,因此只能通过修改density的值来使得等式两边相等。那么可以得出以下公式:
density = 当前设备屏幕总宽度(单位为像素)/ 设计图总宽度(单位为 dp)
在求得density的之后,通过代码来修改系统的density值即可完成适配。
- JMM与volatile关键字
- synchronized的实现原理
- synchronized等待与唤醒机制
- ReentrantLock的实现原理
- ReentrantLock等待与唤醒机制
- CAS、Unsafe类以及Automic并发包
- ThreadLocal的实现原理
- 线程池的实现原理
- Java线程中断机制
- 多线程与并发常见面试题
- Android基础知识汇总
- MVC、MVP与MVVM
- SparseArray实现原理
- ArrayMap的实现原理
- SharedPreferences
- Bitmap
- Activity的启动模式
- Fragment核心原理
- 组件化项目架构搭建
- 组件化WebView架构搭建
- 为什么 Activity.finish() 之后 10s 才 onDestroy ?
- Android系统启动流程
- InputManagerService
- WindowManagerService
- Choreographer详解
- SurfaceFlinger
- ViewRootImpl
- APP启动流程
- Activity启动流程
- PMS 安装与签名校验
- Dalvik 与 ART
- 内存优化策略
- UI界面及卡顿优化
- App启动优化
- ANR问题
- 包体积优化
- APK打包流程
- 电池电量优化
- Android屏幕适配
- 线上性能监控1--线上监控切入点
- 线上性能监控2--Matrix实现原理
- Glide实现原理
- OkHttp实现原理
- Retrofit实现原理
- RxJava实现原理
- RxJava中的线程切换与线程池
- LeakCanary实现原理
- ButterKnife实现原理
- ARouter实现原理
- Tinker实现原理
- 2. 两数相加
- 19.删除链表的倒数第 N 个结点
- 21. 合并两个有序链表
- 24. 两两交换链表中的节点
- 61. 旋转链表
- 86. 分隔链表
- 92. 反转链表 II
- 141. 环形链表
- 160. 相交链表
- 206. 反转链表
- 206 反转链表 扩展
- 234. 回文链表
- 237. 删除链表中的节点
- 445. 两数相加 II
- 面试题 02.02. 返回倒数第 k 个节点
- 面试题 02.08. 环路检测
- 剑指 Offer 06. 从尾到头打印链表
- 剑指 Offer 18. 删除链表的节点
- 剑指 Offer 22. 链表中倒数第k个节点
- 剑指 Offer 35. 复杂链表的复制
- 1. 两数之和
- 11. 盛最多水的容器
- 53. 最大子序和
- 75. 颜色分类
- 124.验证回文串
- 167. 两数之和 II - 输入有序数组 -169. 多数元素
- 189.旋转数组
- 209. 长度最小的子数组
- 283.移动0
- 303.区域和检索 - 数组不可变
- 338. 比特位计数
- 448. 找到所有数组中消失的数字
- 643.有序数组的平方
- 977. 有序数组的平方