美文网首页
屏幕适配(二)--今日头条方案

屏幕适配(二)--今日头条方案

作者: azu_test | 来源:发表于2019-03-12 14:57 被阅读0次

    dp、px、dpi的计算公式

    • px = density * dp;
    • density = dpi / 160;
    • px = dp * (dpi / 160);

    原理

    • UI最终绘制时会把所有尺寸单位(px、dp、sp、pt等)转换成px。
    • 选定一种尺寸单位(dp、sp、pt等)作为我们的适配单位,然后篡改这个单位与px之间的转化比例。即更改density(屏幕密度)值。

    可以看出,设计图宽为375dp,想要保证在所有设备计算得出的px值都是屏幕宽度的话,只能修改 density 值。

    DisplayMetrics

    所有的dp和px的转换都是通过 DisplayMetrics 中相关的值来计算的。

    布局文件中dp的转换方法如下

        TypedValue#applyDimension
        public static float applyDimension(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;
        }
    

    其他场景的dp转换基本上也都是通过DisplayMetrics来计算的,所以只需要修改 DisplayMetrics 中和dp转换相关的变量即可。

    宽维度适配实现

    • px值 = dp值 * metrics.density。每种手机的px值是固定的,UI会给一套固定的设计图,而且我们要通过这套标注去适配其他手机。为了等式成立只能修改metrics.density值。
      metrics.density = Metrics.widthPixels / 375
    • 通过计算出来的density修改dpi
      metrics.densityDpi = int(修改后的metrics.density*160);
    • 更新sp值,要注意用户可能会更改字体大小
      metrics.scaledDensity = 修改后的density * (系统原来的ScaledDensity / 系统原来的Density)
    实现代码
        private void setCustomDensity(Activity activity, final Application application) {
            //application
            final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
            if (sRoncompatDennsity == 0) {
                sRoncompatDennsity = appDisplayMetrics.density;
                sRoncompatScaledDensity = appDisplayMetrics.scaledDensity;
                application.registerComponentCallbacks(new ComponentCallbacks() {
                    @Override
                    public void onConfigurationChanged(Configuration newConfig) {
                        if (newConfig != null && newConfig.fontScale > 0) {
                            sRoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
                        }
                    }
                    @Override
                    public void onLowMemory() {
                    }
                });
            }
            //计算宽为375dp 同理可以设置高为的根据实际情况
            final float targetDensity = appDisplayMetrics.widthPixels / 375;
            final float targetScaledDensity = targetDensity * (sRoncompatScaledDensity / sRoncompatDennsity);
            final int targetDensityDpi = (int) (targetDensity * 160);
    
            appDisplayMetrics.density = targetDensity;
            appDisplayMetrics.densityDpi = targetDensityDpi;
            appDisplayMetrics.scaledDensity = targetScaledDensity;
    
            //activity
            final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
            activityDisplayMetrics.density = targetDensity;
            activityDisplayMetrics.densityDpi = targetDensityDpi;
            activityDisplayMetrics.scaledDensity = targetScaledDensity;
        }
    

    在Activity中调用setContentView()之前调用setCustomDensity()方法即可。

    相关文章

      网友评论

          本文标题:屏幕适配(二)--今日头条方案

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