美文网首页
Android 屏幕适配原理

Android 屏幕适配原理

作者: 折剑游侠 | 来源:发表于2020-06-02 17:42 被阅读0次

本文方案为修改系统density

  • px---------->像素
  • dpi---------->像素密度 对应于DisplayMetrics类中属性densityDpi的值 dpi = density*160
  • density----->屏幕密度 px = dpi*density

Android系统最终会将xml中dp,sp值转换为像素px。通常情况下ui给到我们设计图的单位是px,以设计图最大宽度为参照值,根据屏幕最大宽度算出比例,将得到的值替换系统density。

打个比方:设计图最大宽度500px,手机最大宽度720px,density修改为720/500=1.44。在xml中指定view的宽度为250dp,系统计算得到view宽度250*density=360px。正好占据手机宽度720px的一半,与设计图相符。

以此类推:另一台手机最大宽度1080px,density修改为1080/500=2.16。此时计算得到view宽度250*2.16=540px,正好占据宽度一半。

也就是说根据手机屏幕宽度像素点的不同,依照设计图最大宽度,动态修改系统density值,然后按设计图指定view大小,在不同分辨率设备上表现是一致的。

object AutoSize {
    private var density: Float = 0F//屏幕密度
    private var scaleDensity: Float = 0F//字体缩放比例

    //设计图宽度默认为500px
    @JvmOverloads
    fun init(activity: Activity, width: Float = 500F) {
        val displayMetrics = activity.resources.displayMetrics
        //系统屏幕密度
        density = displayMetrics.density
        //系统字体缩放比例
        scaleDensity = displayMetrics.scaledDensity

        //计算适配屏幕密度、字体缩放比例、像素密度
        val currentDensity = displayMetrics.widthPixels / width
        val currentScaleDensity = currentDensity * (scaleDensity / density)
        val currentDensityDpi = (currentDensity * 160).toInt()

        //替换系统值
        val dm = activity.resources.displayMetrics
        dm.density = currentDensity
        dm.scaledDensity = currentScaleDensity
        dm.densityDpi = currentDensityDpi
    }
}

在setContentView前调用

class AutoSizeActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        AutoSize.init(this)
        setContentView(R.layout.activity_autosize)
    }
}

activity_autosize.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:background="@android:color/holo_orange_dark"
        android:gravity="center"
        android:text="text"
        android:textSize="20sp" />
</RelativeLayout>

运行


可以在BaseActivity中调用,也可以在Application中操作

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
            override fun onActivityPaused(activity: Activity) {
            }

            override fun onActivityStarted(activity: Activity) {
            }

            override fun onActivityDestroyed(activity: Activity) {
            }

            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
            }

            override fun onActivityStopped(activity: Activity) {
            }

            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                AutoSize.init(activity)
            }

            override fun onActivityResumed(activity: Activity) {
            }

        })
    }
}

如果某些Activity不希望适配,写个空接口

interface CancelAdapter

Activity实现接口

class AutoSizeActivity : AppCompatActivity(), CancelAdapter {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_autosize)
    }
}

Application

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
            override fun onActivityPaused(activity: Activity) {
            }

            override fun onActivityStarted(activity: Activity) {
            }

            override fun onActivityDestroyed(activity: Activity) {
            }

            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
            }

            override fun onActivityStopped(activity: Activity) {
            }

            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                if (activity is CancelAdapter) return
                AutoSize.init(activity)
            }

            override fun onActivityResumed(activity: Activity) {
            }

        })
    }
}

某些Activity设计图大小不一致,添加新接口

interface CustomizeAdapter {
    fun getWidth(): Float
}

Activity实现接口

class AutoSizeActivity : AppCompatActivity(), CustomizeAdapter {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_autosize)
    }

    override fun getWidth(): Float {
        return 750F
    }
}

Application

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
            override fun onActivityPaused(activity: Activity) {
            }

            override fun onActivityStarted(activity: Activity) {
            }

            override fun onActivityDestroyed(activity: Activity) {
            }

            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
            }

            override fun onActivityStopped(activity: Activity) {
            }

            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                when (activity) {
                    is CancelAdapter -> return
                    is CustomizeAdapter -> {
                        AutoSize.init(activity, activity.getWidth())
                    }
                    else -> AutoSize.init(activity)

                }
            }

            override fun onActivityResumed(activity: Activity) {
            }

        })
    }
}

占据三分之一宽度


感觉有点像AndroidAutoSize,怎么肥事=。=

相关文章

网友评论

      本文标题:Android 屏幕适配原理

      本文链接:https://www.haomeiwen.com/subject/agguzhtx.html