简介
对于常见的项目中,UI都会以宽为基准来出图,这时就会以固定的屏幕宽度来定稿。但是安卓屏幕各异,密度各不相同,所以不能简单的直接使用dp来定义UI的样式。
DPI
在Android中,DPI表示屏幕像素密度。表示单位长度上对应的像素个数。在resource中有一个displayMetrics管理着对应的值。displayMetrics中有两个重要的参数
- densityDpi,表示屏幕的dpi,dpi的基准为160,即160的dpi时1dp=1px,480的dpi时1dp=3px
- density,即表示上面的比例关系,480dp时density为3。屏幕宽度=density*宽度总dp
屏幕适配
所以这时我们要使屏幕的宽度dp数固定,则density需要为屏幕总宽度/期望dp数,densityDpi再等于计算所得density乘160.大概就可以写出如下简单的适配方法了,这个更改会影响图片的加载放大比例,也会影响到第三方库中 UI相关dp的定义,但一般不会直接使用三方库的UI,所以影响不大
在Application中添加
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class App : Application() {
init {
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityPreCreated(activity: Activity, savedInstanceState: Bundle?) {
super.onActivityPreCreated(activity, savedInstanceState)
// 在activity onCreate之前去更改,因为在setContentView时就会开始去生成view树了
val appDisplayMetrics = resources.displayMetrics
val activityDisplayMetrics = activity.resources.displayMetrics
activityDisplayMetrics.density = appDisplayMetrics.density
activityDisplayMetrics.densityDpi = appDisplayMetrics.densityDpi
}
//其实在onActivityCreated中也可以,这个方法使super.onCreate中调用的
// ...
})
}
override fun onCreate() {
super.onCreate()
val appDisplayMetrics = resources.displayMetrics
// 这里举例期望的宽度为375dp
val targetDensity = 1.0f * appDisplayMetrics.widthPixels / 375
val targetDensityDpi = (targetDensity * 160).toInt()
// 更改app中默认的参数
appDisplayMetrics.density = targetDensity
appDisplayMetrics.densityDpi = targetDensityDpi
}
companion object {
var activity: Activity? = null
}
}