屏幕適配:修改屏幕像素密度,隨便設dp

前提

平時xml中view的寬高單位都是dp居多,我們的設計師一般會選擇一款機型的屏幕尺寸作爲設計的目標尺寸。

那麼,如何根據目標尺寸的屏幕密度,適配我們種類繁多的機型?

實現目標

將以dp作爲單位,以目標尺寸標註的寬高,和當前機型的比例,動態進行屏幕適配。
例如:設計尺寸爲360dp寬,我們的view設置180dp寬。那麼,該view在任何屏幕尺寸下,都將佔用屏幕一半的尺寸;

瞭解參數

在上代碼前,先了解下待會用到的參數含義:

  • density
    當前機型的屏幕密度,標準屏幕密度是每平方英寸有160個像素,如果當前機型每平方英寸有320個像素,即density = (320 / 160)= 2;
  • scaleDensity
    代表的是字體的屏幕密度,默認情況下:scaleDensity = density;
  • densityDpi
    表示的就是每平方英寸顯示的像素點個數。
    如:160個像素點 即densityDpi=160;

上代碼

代碼其實非常簡單,直接從DisplayMetrics中獲取。

    private final static float WIDTH = 360;//適配機型的寬爲360dp,屏幕寬/屏幕密度=360dp

    private static float appDensity;
    private static float appScaleDensity;

    public static void setDensity(Application application, Activity activity) {
        //獲取當前app的屏幕顯示信息
        DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();

        appDensity = displayMetrics.density;
        appScaleDensity = displayMetrics.scaledDensity;

        //計算等比縮放後的density和scaleDensity
        //WIDTH相對於所有屏幕寬度都是相等的,它是用dp作爲單位,所以 屏幕寬度/屏幕密度=WIDTH
        //targetDensity = targetWidht/WIDTH
        float targetDensity = displayMetrics.widthPixels / WIDTH;
        //appScaleDensity/appDensity=targetScaleDensity/targetDensity;
        float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
        int targetDensityDpi = (int) (targetDensity * 160);

        //替換activity的density,appdensity,densityDpi
        DisplayMetrics aDisplayMertics = activity.getResources().getDisplayMetrics();
        aDisplayMertics.density = targetDensity;
        aDisplayMertics.scaledDensity = targetScaleDensity;
        aDisplayMertics.densityDpi = targetDensityDpi;
    }
}

思路講解,計算

首先我們需要獲取當前機型的屏幕密度信息:appDensity,appScaleDensity

我們的設計尺寸會根據默認機型計算出一個固定的以dp爲單位的寬度:WIDTH

比如:默認機型的寬高爲1080*1920,該設備的屏幕密度爲3
那麼WIDTH = 1080/3 = 360dp;因此所有適配機型的寬也就等於360dp。
根據 屏幕寬度 / 屏幕密度=WIDTH公式,現在知道屏幕寬度和WIDTH,也就能求出:屏幕密度=屏幕寬度 / WIDHT;

現在屏幕寬度(dp):targetDensity = displayMetrics.widthPixels / WIDTH 求出。

接下來,就需要求出適配機型的scaleDensity

appScaleDensity / appDensity = targetScaleDensity / targetDensity ;

targetScaleDensity = targetDensity * (appScaleDensity / appDensity) ;

densityDpi = density * 160 ;

最後,把獲取到的數據,設置到activity的displayMetrics中。

計算出來後,我們需要在繪製view之前先設置好

在onCreate中的setContentView之前添加

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
      //在繪製前設置density
    DensityUtils.setDensity(this.application, this)
    setContentView(R.layout.activity_screen_adapter2)
}

現在,我們的設計尺寸寬度爲360dp,我們設置view的寬度爲180dp,應該是佔用屏幕一半尺寸。

<RelativeLayout 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=“.screenAdapter2.ScreenAdapter2Activity”>

    <TextView
        android:id=“@+id/tv1”
        android:layout_width=“180dp”
        android:layout_height=“180dp”
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:background="#f00" />

    <TextView
        android:layout_width="180dp"
        android:layout_height="180dp"
        android:layout_below="@id/tv1"
        android:layout_toRightOf="@id/tv1"
        android:background="#0f0" />

</RelativeLayout>

顯示效果:

 

字體的縮放監聽

以上代碼在字體發生改變時,不會根據字體設置相應的發生改變
我們需要監聽字體改變事件,再重新計算scaleDensity;

//完整代碼
public static void setDensity(final Application application, Activity activity) {
    //獲取當前app的屏幕顯示信息
    DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();

    appDensity = displayMetrics.density;
    appScaleDensity = displayMetrics.scaledDensity;

    //監聽字體改變,重新獲取scaleDensity
    application.registerComponentCallbacks(new ComponentCallbacks() {
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            if (newConfig != null && newConfig.fontScale > 0) {
                appScaleDensity = application.getResources().getDisplayMetrics().scaledDensity;
            }
        }

        @Override
        public void onLowMemory() {

        }
    });

    //計算等比縮放後的density和scaleDensity
    //WIDTH相對於所有屏幕寬度都是相等的,它是用dp作爲單位,所以 屏幕寬度/屏幕密度=WIDTH
    //targetDensity = targetWidht/WIDTH
    float targetDensity = displayMetrics.widthPixels / WIDTH;
    //appScaleDensity/appDensity=targetScaleDensity/targetDensity;
    float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
    int targetDensityDpi = (int) (targetDensity * 160);

    //替換activity的density,appdensity,densityDpi
    DisplayMetrics aDisplayMertics = activity.getResources().getDisplayMetrics();
    aDisplayMertics.density = targetDensity;
    aDisplayMertics.scaledDensity = targetScaleDensity;
    aDisplayMertics.densityDpi = targetDensityDpi;
}

 

最後

如果你看到了這裏,覺得文章寫得不錯就給個讚唄!歡迎大家評論討論!如果你覺得那裏值得改進的,請給我留言。一定會認真查詢,修正不足,定期免費分享技術乾貨。感興趣的小夥伴可以點一下關注哦。謝謝!

 

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