关于今日头条屏幕适配

在Android开发中,由于Android碎片化严重,屏幕分辨率千奇百怪,而想要在各种分辨率的设备上显示基本一致的效果,适配成本越来越高。虽然Android官方提供了dp单位来适配,但其在各种奇怪分辨率下表现却不尽如人意,因此今日头条适配就出来了,适配极其简单,主要是一些原理。

 

android中的dp在渲染前会将dp转为px,计算公式:

  • px = density * dp;

  • density = dpi / 160;

  • px = dp * (dpi / 160);

  •  

而dpi是根据屏幕真实的分辨率和尺寸来计算的,每个设备都可能不一样的,因为安卓的碎片化太严重导致的。

废话就不多说了,直接上代码

 

假如UI设计师给的是宽度为360dp的设计稿


/**
 * 概念性:
 * 1、什么是px(分辨率)为什么不能用px?为什么有dp单位?为什么dp不能适配所有屏幕?到最后的屏幕适配的解决方案
 * 2、什么是屏幕尺寸(英寸)
 * 3、什么是屏幕密度dpi(每英寸有多少像素点)
 * 4、什么是密度(为了适配谷歌自定义的密度)
 * 5、什么是dp(与屏幕密度无关的计量单位)
 *
 * 今日头条的解决方案?
 * 假如固定设计图的宽或者高 单位是dp 360dp
 *
 * px = 360dp * 密度 每种手机的分辨率不一样:假如现在有这几种720px 1080px 1440px      * 2048px
 *
 * 360 = px / 密度
 *
 * 密度 = px / 360
 *
 */

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        // 100dp 的按钮在所有屏幕上占的比例是一样的  屏幕的分辨率是px值
        //原始比例 是不是 0.27777

        //不同手机的分辨率:720px 1080px 1440px 2048px
        //不同手机分辨率对应的密度:2,3,4,5.689
        //在不同设备上100dp对应的px值:200px 300px 400px 569px 0.277

        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        int widthPx = displayMetrics.widthPixels;//得到屏幕宽的分辨率
        int heightPx = displayMetrics.heightPixels;//得到屏幕高的分辨率
        float density = displayMetrics.density;//密度
        float scaledDensity = displayMetrics.scaledDensity;//与字体大小相关的密度
        //原始的scaledDensity 比上 原始的density
        float a = scaledDensity / density; //计算变化后的比例 原始系统的比例

        float newDensity = widthPx / 360f;//真实的密度  360是dp的值

        float newscaledDensity = newDensity * a;


        displayMetrics.density = newDensity;//决定布局尺寸

        displayMetrics.scaledDensity = newscaledDensity;//决定字体大小

        setContentView(R.layout.activity_main);
        // 360dp 设计图宽度

        TextView textView = findViewById(R.id.showResult);
        textView.setText("widthPx = "+widthPx+",heightPx = "+heightPx+",density = "+density+",newDensity="+newDensity);
        Log.i("abc","widthPx = "+widthPx+",heightPx = "+heightPx+",density = "+density);
    }
}

然由于电脑原因展示不了效果各位请自行运行下载各个手机上测试

由于我是按照UI设计稿为360dp来计算的各位可以先复制我的测试下,至于布局文件在下面

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:background="#fff0"
        android:id="@+id/showResult"
        android:layout_width="180dp"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        />

</LinearLayout>

各位自行测试,如果可以 ,假如你项目用的是MVP的话就把这个复制到BaseActivity中zhuy注意要在setContentView()之前设置

至于360dp是我的测试,你们可以按照zi自己的UI图来设置宽度

 

//下面这个是封装好的适配工具类只需调用即可

public class Density {
    private static float appDensity;
    private static float appScaledDensity;
    private static DisplayMetrics appDisplayMetrics;
    /**
     * 用来参照的的width
     */
    private static float WIDTH;
 
    public static void setDensity(@NonNull final Application application, float width) {
        appDisplayMetrics = application.getResources().getDisplayMetrics();
        WIDTH = width;
        registerActivityLifecycleCallbacks(application);
 
        if (appDensity == 0) {
            //初始化的时候赋值
            appDensity = appDisplayMetrics.density;
            appScaledDensity = appDisplayMetrics.scaledDensity;
 
            //添加字体变化的监听
            application.registerComponentCallbacks(new ComponentCallbacks() {
                @Override
                public void onConfigurationChanged(Configuration newConfig) {
                    //字体改变后,将appScaledDensity重新赋值
                    if (newConfig != null && newConfig.fontScale > 0) {
                        appScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
                    }
                }
 
                @Override
                public void onLowMemory() {
                }
            });
        }
    }
 
 
    private static void setDefault(Activity activity) {
        setAppOrientation(activity);
    }
 
    private static void setAppOrientation(@Nullable Activity activity) {
 
        float targetDensity = 0;
        try {
            targetDensity = appDisplayMetrics.widthPixels / WIDTH;
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
 
        float targetScaledDensity = targetDensity * (appScaledDensity / appDensity);
        int targetDensityDpi = (int) (160 * targetDensity);
 
        /**
         *
         * 最后在这里将修改过后的值赋给系统参数
         *
         * 只修改Activity的density值
         */
 
        DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
        activityDisplayMetrics.density = targetDensity;
        activityDisplayMetrics.scaledDensity = targetScaledDensity;
        activityDisplayMetrics.densityDpi = targetDensityDpi;
    }
 
 
    private static void registerActivityLifecycleCallbacks(Application application) {
        application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                setDefault(activity);
            }
            @Override
            public void onActivityStarted(Activity activity) {
            }
            @Override
            public void onActivityResumed(Activity activity) {
            }
            @Override
            public void onActivityPaused(Activity activity) {
            }
            @Override
            public void onActivityStopped(Activity activity) {
            }
            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            }
            @Override
            public void onActivityDestroyed(Activity activity) {
 
            }
        });
    }

到此结束

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章