前言:屏幕适配说白了就是将设计图按宽或高进行整体等比缩放。
方案:如设计图分辨率(宽360px,高560px),手机屏分别率(宽1080px,高1920px),按宽进行适配需要将设计图的控件尺寸宽高等比放大(手机屏宽1080px / 设计图宽360px = 3)倍,而获取xml中定义的所有控件再分别对宽高放大3倍,这操作我们通过代码实现,显然很繁重,然而我就将这部分工作交给系统,要知道控件在系统中宽高最终都转成px(px= density * dp),我们就巧妙利用系统的转换公式,将density = 手机屏宽 / 设计图宽,在xml中直接将设计图px值作为dp值使用即可(如设计图控件宽360px,那么xml中宽定义为360dp)。同理按高适配只需将density = 手机屏高 / 设计图高,在xml中使用dp系统则自行进行缩放。如果有的页面需要按宽有的页面需要按高适配或同一页面不同控件有的需按高适配有的需按高适配,我们可以利用(px = xdpi / 72 * pt)将xdpi = 手机屏高 / 设计图高 * 72,xml中将需要按高度适配的控件宽高定义成pt,按宽度适配的控件宽高定义成dp即可。
实现:只需在application的onCreate方法中调用ScreenUtil的init方法即可
object ScreenUtil {
fun init(application: Application, designWith: Float, designHeight: Float){
val appDisplayMetrics = application.resources.displayMetrics
val screenWith = appDisplayMetrics.widthPixels //屏幕宽度px
val screenHeight = appDisplayMetrics.heightPixels //屏幕高度px
val densityDef = appDisplayMetrics.density //系统默认density
appDisplayMetrics.density = screenWith / designWith
appDisplayMetrics.densityDpi = (appDisplayMetrics.density * 160).toInt()
appDisplayMetrics.xdpi = designHeight / screenHeight * 72
//字体跟随系统设置,默认scaleDensity==density
appDisplayMetrics.scaledDensity = appDisplayMetrics.density * (appDisplayMetrics.scaledDensity / densityDef)
//监听系统字体切换
application.registerComponentCallbacks(object : ComponentCallbacks{
override fun onLowMemory() {}
override fun onConfigurationChanged(newConfig: Configuration?) {
newConfig?.let {
if (it.fontScale > 0){
appDisplayMetrics.scaledDensity = appDisplayMetrics.density * (appDisplayMetrics.scaledDensity / densityDef)
}
}
}
})
//activity生命周期监听
application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks{
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
activity?.let {
val activityDisplayMetrics = it.resources.displayMetrics
activityDisplayMetrics.density = it.application.resources.displayMetrics.density
activityDisplayMetrics.scaledDensity = it.application.resources.displayMetrics.scaledDensity
activityDisplayMetrics.densityDpi = it.application.resources.displayMetrics.densityDpi
activityDisplayMetrics.xdpi = it.application.resources.displayMetrics.xdpi
}
}
override fun onActivityPaused(activity: Activity?) {}
override fun onActivityResumed(activity: Activity?) {}
override fun onActivityStarted(activity: Activity?) {}
override fun onActivityDestroyed(activity: Activity?) {}
override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {}
override fun onActivityStopped(activity: Activity?) {}
})
}
}
补充说明:
1、字体大小由scaledDensity控制,默认scaledDensity==density,当用户修改系统字体后scaledDensity缩放至(当前的scaledDensity / 系统默认density)倍,如无需字体跟随系统设置可直接将scaledDensity设置为density同时也无需监听系统字体切换
2、density=dpi*160 dpi为软件层面在系统配置文件定义的值,而ppi为物理层面一英寸对应的像素值
3、宽高限定符适配方案(需要定义需要适配的机型分辨率):values-800x480 如果手机屏幕分辨率不满足我们定义的将使用默认的values
4、sw限定符适配(需要定义需要适配的机型宽度dp):values-sw350dp 如果手机屏幕dp不满足我们定义的系统会向下寻找最近的资源文件