Android 屏幕适配

326 阅读3分钟

Android 屏幕适配

背景

背景就是要把之前在手机上做的一个项目移植到一个小屏设备上,但是前期小屏设备又没有到位,所以才会需要屏幕适配。

本文主要是记录作者在适配的过程中用到的一些知识以及参考的文章,做个总结,以便以后遇到时可以更方便的用起来。

adb命令修改设备屏幕参数

使用adb命令可以直接修改屏幕分辨率,这样大大的方便了屏幕适配的工作,你可以直接在已有的设备上看到不同分辨率下的效果。

  1. 查看屏幕尺寸
    adb shell wm size
    
  2. 查看屏幕密度
    adb shell wm density
    
  3. 同时查看屏幕尺寸和密度
    adb shell wm size && adb shell wm density
    
  4. 设置屏幕尺寸
    adb shell wm size 1440x3216
    
  5. 设置屏幕密度
    adb shell wm density 640
    
  6. 同时设置屏幕尺寸和密度
    adb shell wm size 1440x3216 && adb shell wm density 640
    

运行时代码适配屏幕

在应用启动时对屏幕进行适配,可以进行宽度适配或者高度适配。

经典文章,致敬前人:

  1. 今日头条的适配方案: 一种极低成本的Android屏幕适配方式(mp.weixin.qq.com/s/d9QCoBP6k…

  2. JessYan的AndroidAutoSize介绍及仓库地址:

今日头条屏幕适配方案终极版正式发布(juejin.cn/post/684490…

AndroidAutoSize(github.com/JessYanCodi…

安卓系统在渲染前会把dp、sp转换成px,而转换的比例因子就是density和scaledDensity,具体关系就是:

  • px = density * dp
  • density = densityDpi / 160
  • densityDpi=+高(单位px)屏幕尺寸(单位inch)densityDpi= \frac {\sqrt{宽*宽 + 高*高(单位px)}} {屏幕尺寸(单位inch)}

插播:markdown插入公式参考(zhuanlan.zhihu.com/p/158156773…

dp与px的关联就是density,进行适配需要修改density,除了density,还有一个 scaledDensity,这个参数是字体缩放因子,一般和density相等,但是调节系统字体大小后会改变这个值。

density、scaledDensity和densityDpi都是displayMetrics中的变量,而displayMetrics可以通过3种方式获得,但每个的作用范围是不同的:

  1. 系统的屏幕尺寸:val systemDM = Resources.getSystem().displayMetrics
  2. app整体的屏幕尺寸:val appDM = activity.application.resources.displayMetrics
  3. activity的屏幕尺寸:val activityDM = activity.resources.displayMetrics

但是在Android8.0之后, appDM 和 activityDM 获取的同一个类。Resources.getSystem().displayMetrics这个是整个Android设备的,一般不能改。

屏幕适配的核心代码如下:

根据宽度进行屏幕适配

    /**
     * 根据UI设计尺寸的宽度适配屏幕
     *
     * @param application
     * @param uiWidthDp
     */
    fun adapterScreenByUIWidth(application: Application, uiWidthDp: Int) {
        // app整体的屏幕尺寸
        val appDM = application.resources.displayMetrics
        if (targetDensity != 0f) {
            appDM.density = targetDensity
            appDM.scaledDensity = targetScaledDensity
            appDM.densityDpi = targetDensityDpi
            return
        }

        // 系统的屏幕尺寸
        val systemDM = Resources.getSystem().displayMetrics
        appDM.density = appDM.widthPixels.toFloat() / uiWidthDp
        appDM.scaledDensity = appDM.density * (systemDM.scaledDensity / systemDM.density)
        appDM.densityDpi = (160 * appDM.density).toInt()
        application.registerComponentCallbacks(object : ComponentCallbacks {
            override fun onConfigurationChanged(newConfig: Configuration) {
                adapterScreenByUIWidth(application, uiWidthDp)
            }

            override fun onLowMemory() {}
        })
        targetDensity = appDM.density
        targetScaledDensity = appDM.scaledDensity
        targetDensityDpi = appDM.densityDpi
    }

根据高度进行屏幕适配

    /**
     * 根据UI设计尺寸的高度适配屏幕
     *
     * @param application
     * @param uiHeightDp
     */
    fun adapterScreenByUIHeight(application: Application, uiHeightDp: Int) {
        // app整体的屏幕尺寸
        val appDM = application.resources.displayMetrics
        if (targetDensity != 0f) {
            appDM.density = targetDensity
            appDM.scaledDensity = targetScaledDensity
            appDM.densityDpi = targetDensityDpi
            return
        }

        // 系统的屏幕尺寸
        val systemDM = Resources.getSystem().displayMetrics
        appDM.density = appDM.heightPixels.toFloat() / uiHeightDp
        appDM.scaledDensity = appDM.density * (systemDM.scaledDensity / systemDM.density)
        appDM.densityDpi = (160 * appDM.density).toInt()
        application.registerComponentCallbacks(object : ComponentCallbacks {
            override fun onConfigurationChanged(newConfig: Configuration) {
                adapterScreenByUIHeight(application, uiHeightDp)
            }

            override fun onLowMemory() {}
        })
        targetDensity = appDM.density
        targetScaledDensity = appDM.scaledDensity
        targetDensityDpi = appDM.densityDpi
    }

恢复系统屏幕密度

    /**
     * 恢复系统原来的density
     *
     * @param activity
     */
    fun resetScreen(activity: Activity) {
        // 系统的屏幕尺寸
        val systemDM = Resources.getSystem().displayMetrics
        // app整体的屏幕尺寸
        val appDM = activity.application.resources.displayMetrics
        // activity的屏幕尺寸
        val activityDM = activity.resources.displayMetrics
        activityDM.density = systemDM.density
        activityDM.scaledDensity = systemDM.scaledDensity
        activityDM.densityDpi = systemDM.densityDpi
        appDM.density = systemDM.density
        appDM.scaledDensity = systemDM.scaledDensity
        appDM.densityDpi = systemDM.densityDpi
    }