Android兼容之屏幕适配

背景
Android碎片化严重,屏幕分辨率千奇百怪,虽然官方提供了dp和sp,但是适配还是不尽人意,下面提供一种简单且无侵入的适配方案
必备知识点
Android会在渲染前将dp或者sp都会转化为px,计算公式:
px = dp * density;
px = sp * scaledDensity;
density = dpi / 160;
所以: px = dp * (dpi / 160)
其中:dpi(像素密度)根据分辨率和屏幕尺寸计算出来的
在这里插入图片描述
示例:屏幕分辨率为:1920*1080,屏幕尺寸为5吋的话,那么dpi为440

存在的问题
假设我们UI设计图是按屏幕宽度为360dp来设计的,那么在上述设备上,屏幕宽度其实为1080/(440/160)=392.7dp,也就是屏幕是比设计图要宽的。这种情况下, 即使使用dp也是无法在不同设备上显示为同样效果的。 同时还存在部分设备屏幕宽度不足360dp,这时就会导致按360dp宽度来开发实际显示不全的情况。
而且上述屏幕尺寸、分辨率和像素密度的关系,很多设备并没有按此规则来实现, 因此dpi的值非常乱,没有规律可循,从而导致使用dp适配效果差强人意

解决方案:

由于px = dp * density;如果设计图宽为360dp,想要保证在所有设备计算得出的px值都正好是屏幕宽度的话,我们只能修改 density 的值;
density 是 DisplayMetrics 中的成员变量,而 DisplayMetrics 实例通过Resources#getDisplayMetrics 可以获得,而Resouces通过Activity或者Application的Context获得。
先来熟悉下 DisplayMetrics 中和适配相关的几个变量:

DisplayMetrics#density 就是上述的density
DisplayMetrics#densityDpi 就是上述的dpi
DisplayMetrics#scaledDensity 字体的缩放因子,正常情况下和density相等,但是调节系统字体大小后会改变这个值

我们知道布局文件最后都是通过

 package android.util;
 public class TypedValue {
    
    
 public static float applyDimension(@ComplexDimensionUnit int unit, float value,
                                       DisplayMetrics metrics)
    {
    
    
        switch (unit) {
    
    
        case COMPLEX_UNIT_PX:
            return value;
        case COMPLEX_UNIT_DIP:
            return value * metrics.density;
        case COMPLEX_UNIT_SP:
            return value * metrics.scaledDensity;
        case COMPLEX_UNIT_PT:
            return value * metrics.xdpi * (1.0f/72);
        case COMPLEX_UNIT_IN:
            return value * metrics.xdpi;
        case COMPLEX_UNIT_MM:
            return value * metrics.xdpi * (1.0f/25.4f);
        }
        return 0;
    }
    }

方案就是把所有的屏幕都按照360dp或者其它固定的dp做处理,通过修改density值,保证dp转换后的px大小都是一致的
density = 设备真实宽(单位px) / 360
在基类activity和基类fragment中在onCreatef方法中处理

   private static void adaptScreenVertical(Activity activity) {
    
    
        DisplayMetrics appDisplayMetrics = activity.getApplicationContext().getResources().getDisplayMetrics();
        if (sNoncompatDensity == 0) {
    
    
            sNoncompatDensity = appDisplayMetrics.density;
            sNoncompatScaledDensity = appDisplayMetrics.scaledDensity;
            activity.getApplication().registerComponentCallbacks(new ComponentCallbacks2() {
    
    
                @Override
                public void onTrimMemory(int level) {
    
    

                }

                @Override
                public void onConfigurationChanged(@NonNull Configuration newConfig) {
    
    
                    if (newConfig != null && newConfig.fontScale > 0) {
    
    
                        sNoncompatScaledDensity = activity.getApplication().getResources().getDisplayMetrics().scaledDensity;
                    }
                }

                @Override
                public void onLowMemory() {
    
    

                }
            });
        }

        /**
         *   px = dp * (dpi / 160)
         *
         *   density = dpi / 160
         *
         *   px = dp * density
         *
         *   dpi 像素密度- 每英寸的像素点数,数值越高显示越细腻
         *    dpi=  (宽^2 + 高^2) =  对象线= 2203    1080 1920
         *      屏幕大小是5英寸,所以2203/5 440
         *
         *
         *
          */

        final float targetDensity = appDisplayMetrics.widthPixels / 360;
        final float targetScaleDensity = targetDensity * (sNoncompatScaledDensity / sNoncompatDensity);
        final int targetDensityDpi = (int) (targetDensity * 160);
        appDisplayMetrics.density = targetDensity;
        appDisplayMetrics.scaledDensity = targetScaleDensity;
        appDisplayMetrics.densityDpi = targetDensityDpi;
        Log.d("getDensity", "app: " + targetDensity + "/scale=" + targetScaleDensity + "/dpi=" + targetDensityDpi);

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

参考文档:字节跳动技术方案

猜你喜欢

转载自blog.csdn.net/ixiaoma/article/details/128492992