Android 屏幕适配(实用版)

在进行屏幕适配开始之前有必要先了解一下 dp、px、sp、dpi这些都是代表了什么

一、基本概念

dp:(device independent pixels)== dip 虚拟像素,用于限定控件尺寸

px:像素点

sp:同dp相似,只不过更多的是用于控件字体大小

dpi:(dots per inch)对角线每英寸的像素点的个数也就是像素密度

density:翻译过来就是 密度

二、计算公式

px = density * dp

density = dpi / 160 

dpi = \frac{\sqrt{height^2+width^2}}{size}      size ——屏幕尺寸(inch)

三、dp适配的效果图

这里看一下未进行适配时候的效果图  这三者的分辨率 分别为 400* 800(4.0)  1080 * 1920(4.95)  1440 * 2560 (5.96)

由于density不是固定不变的,所以每个分辨率不同的设备他们的density都肯定不相等,这样就会造成每个设备的宽/高对应的总dp都是不同的,上图中 dpi分别是:223、445、493对应的density是 1.4、2.78、3,那么总的dp = width(px)/density 分别为

286、388、480 图中TextView 使用了px像素, ImageView采用的是dp两者对比能看出来差距还是非常大的,dp单位在设备间的差距相对px是小很多的 这也就是为什么在做界面的时候没有人使用px而是使用dp的原因。

四、使用smallWidth适配

原理:限定符适配原理与屏幕分辨率限定符适配原理一样的,系统会根据规则去寻找res文件中匹配的 dimens.xml 资源文件。区别就在于屏幕分辨率限定符适配是拿 px 值等比例缩放,而 smallestWidth 限定符适配是改用了dp。

网上有很多现成的不同尺寸的value-sw**dp 可以直接copy 也可以通过插件的的方式一键生成

这里介绍一下生成插件生成的方式:

首先settings - plugins 找到SmallestWidth Dimens 插件 下载安装 重启AS 

ALT + P 快捷键唤出插件 ,图中design width 设计稿像素 根据自己的来,默认输入360即可,最终生成对应的资源文件,直接使用就可以了

看效果:

验证方案:(系统在寻找对应资源文件的时候,如果找不到对应会就近选择一个相近的资源文件使用)

400 * 800 分辨率的手机,dpi为223,我们添加了一个200dp的控件

density = dpi / 160 = 1.4

屏幕总宽度 dp = 400px / 1.4 = 285

资源文件value-sw300dp sw-200dp = 155.6dp

计算px = dp * density = 217.84

屏幕占比:217.84 / 400 = 0.54 

1080 * 1920 分辨率的手机,dpi 为 445,同样是200dp的控件

density = dpi / 160 = 2.78

屏幕总宽度 dp = 1080px / 2.78 = 388

资源文件value-sw380dp sw200dp = 211.2dp

计算px = 211.2 * 2.78 = 587.136

屏幕占比:587.136  / 1080 = 0.54

1440 * 2560 分辨率的手机,dpi为493 ,同样的200dp控件

density = 493 / 160 = 3

屏幕总宽度dp = 1440px / 3 = 467

资源文件value-sw460dp sw200dp = 255.6dp

计算px = 255.6 * 3 = 766.8

屏幕占比:766.8 / 1440 = 0.53

通过上述计算 最终得到的屏幕占比 误差几乎可以忽略不计,可以达到很好的屏幕适配。

优点

  1. 非常稳定,极低概率出现意外
  2. 不会有任何性能的损耗
  3. 适配范围可自由控制,不会影响其他三方库
  4. 在插件的配合下,学习成本低

缺点

  1. 侵入性高,在所有地方都需要引用。
  2. 还是没有办法覆盖所有的机型分辨率,部分机型可能适配效果还是不佳
  3. 不能以高度为基准进行适配
  4. 生成很多文件,增大APP体积1~2M

 五、今日头条适配方案

今日头条屏幕适配方案的核心原理在于,根据公式计算出density

假设我们的设计图宽度是360dp 那么density = 屏幕宽度 / 360 ,得到这个数值之后通过系统的api接口来进行数值修改,达到屏幕适配的目的

验证方案:

400 * 800分辨率的手机,设置一个TextView为200dp宽,设计图宽度为360dp

density = (屏幕宽度 400 )/ 360 = 1.11

view宽度 = 1.11 * 200dp = 222.22px

屏幕占比 = 222.22px / 400 px = 0.56

1080* 1920分辨率的手机,设置一个TextView为200dp宽,设计图宽度为360dp

density = (屏幕宽度 1080)/ 360 = 3

view宽度 = 3* 200dp = 600 px

屏幕占比 = 600px / 1080px = 0.56

1440* 2560 分辨率的手机,设置一个TextView为200dp宽,设计图宽度为360dp

density = (屏幕宽度 1440)/ 360 = 4

view宽度 = 4* 200dp = 800 px

屏幕占比 = 800px / 1440px = 0.56

最终我们通过计算得到的数值都是相等的,没有一点误差

优点

  1. 使用成本非常低,操作非常简单
  2. 侵入性非常低
  3. 可适配三方库的控件和系统的控件

缺点

  1. 会全局影响APP的控件大小,例如一些第三方库控件,他们设计的时候可能设计图尺寸并不是像我们一样是375dp,这样就会导致控件大小变形等一些问题。

 那么如何修改系统的density,直接在activity的oncreate方法中运行下面的方法即可

 /**
     * 屏幕适配
     * 设计图宽360dp
     */
    private static float sNoncompatDensity;
    private static float sNoncompatScaledDensity;
    public static void setCustomDensity(@NonNull Activity activity, @NonNull final Application application) {
        DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
        if (sNoncompatDensity == 0) {
            sNoncompatDensity = appDisplayMetrics.density;
            sNoncompatScaledDensity = appDisplayMetrics.scaledDensity;
            application.registerComponentCallbacks(new ComponentCallbacks() {
                @Override
                public void onConfigurationChanged(Configuration newConfig) {
                    if (newConfig != null && newConfig.fontScale > 0) {
                        sNoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
                    }
                }

                @Override
                public void onLowMemory() {

                }
            });
        }
        float targetDensity = appDisplayMetrics.widthPixels / 360;
        float targetScaledDensity = targetDensity * (sNoncompatScaledDensity / sNoncompatDensity);
        int targetDensityDpi = (int) (160 * targetDensity);

        appDisplayMetrics.density = targetDensity;
        appDisplayMetrics.scaledDensity = targetScaledDensity;
        appDisplayMetrics.densityDpi = targetDensityDpi;

        DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
        activityDisplayMetrics.density = targetDensity;
        activityDisplayMetrics.scaledDensity = targetScaledDensity;
        activityDisplayMetrics.densityDpi = targetDensityDpi;
    }

总结:通过对上述两种屏幕适配方式的对比,smallWidth存在一定的差异,而通过修改density的方式能够完美实现屏幕的适配,我们做屏幕适配最终的目的就是实现在不同尺寸的手机上,同一个控件在屏幕的占比相等,所以更优选的方案还是第二种方案

参考链接:Android屏幕适配方案分析

                  Android屏幕适配之修改density

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值