關於今日頭條屏幕適配

在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) {
 
            }
        });
    }

到此結束

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