[Android]今日頭條的螢幕適配方案,簡單又粗暴!

小鴻洋發表於2018-09-14

 

有個大佬以今日頭條的方案為基礎,結合自己的開發經驗,封裝了一個螢幕適配庫,有興趣的可以瞭解一下.

我先簡單說一下這個方案的思路,它是通過修改density值,強行把所有不同尺寸解析度的手機的寬度dp值改成一個統一的值,這樣就解決了所有的適配問題。

比如,設計稿寬度是360px,那麼開發這邊就會把目標dp值設為360dp,在不同的裝置中,動態修改density值,從而保證(手機畫素寬度)px/density這個值始終是360dp,這樣的話,就能保證UI在不同的裝置上表現一致了。

這個方案侵入性很低,而且也沒有涉及私有API,應該也是極不錯的方案,我暫時也想不到強行修改density是否會有其他影響,既然有今日頭條的大廠在用,穩定性應當是有保證的。

但是根據我的觀察,這套方案對老專案是不太友好的,因為修改了系統的density值之後,整個佈局的實際尺寸都會發生改變,如果想要在老專案檔案中使用,恐怕整個佈局檔案中的尺寸都可能要重新按照設計稿修改一遍才行。因此,如果你是在維護或者改造老專案,使用這套方案就要三思了。

上程式碼(做了下改動):

需要初始化一下:

import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.res.Configuration;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.DisplayMetrics;

/**
 * Created by SouShin on 2018/8/20842.
 * 通過修改系統引數來適配android裝置
 */

public class DensityUtils {
    private static float appDensity;
    private static float appScaledDensity;
    private static DisplayMetrics appDisplayMetrics;
    private static int barHeight;
    public final static String WIDTH = "width";
    public final static String HEIGHT = "height";

    /**
     * 在Application裡初始化一下
     * @param application
     */
    public static void setDensity(@NonNull Application application) {
        //獲取application的DisplayMetrics
        appDisplayMetrics = application.getResources().getDisplayMetrics();
        //獲取狀態列高度
        barHeight = getStatusBarHeight(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() {
                }
            });
    }
}

/**
 * 此方法在BaseActivity中做初始化(如果不封裝BaseActivity的話,直接用下面那個方法就好)
 * 在setContentView()之前設定
 * @param activity
 */
public static void setDefault(Activity activity) {
    setAppOrientation(activity, WIDTH);
}

/**
 * 此方法用於在某一個Activity裡面更改適配的方向
 * 在setContentView()之前設定
 * @param activity
 * @param orientation
 */
public static void setOrientation(Activity activity, String orientation) {
    setAppOrientation(activity, orientation);
}

/**
 * targetDensity
 * targetScaledDensity
 * targetDensityDpi
 * 這三個引數是統一修改過後的值
 * orientation:方向值,傳入width或height
 */
private static void setAppOrientation(@Nullable Activity activity, String orientation) {

    float targetDensity;

    if (orientation.equals("height")) {
        targetDensity = (appDisplayMetrics.heightPixels - barHeight) / 667f;//設計圖的高度 單位:dp
    } else {
        targetDensity = appDisplayMetrics.widthPixels / 360f;//設計圖的寬度 單位:dp
    }

    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;
}

/**
 * 獲取狀態列高度
 *
 * @param context
 * @return
 */
public static int getStatusBarHeight(Context context) {
    int result = 0;
    int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = context.getResources().getDimensionPixelSize(resourceId);
    }
    return result;
    }
}

 

 

import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.res.Configuration;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.DisplayMetrics;

/**
 * Created by SouShin on 2018/8/20842.
 * 通過修改系統引數來適配android裝置
 */

public class DensityUtils {
    private static float appDensity;
    private static float appScaledDensity;
    private static DisplayMetrics appDisplayMetrics;
    private static int barHeight;
    public final static String WIDTH = "width";
    public final static String HEIGHT = "height";

    /**
     * 在Application裡初始化一下
     * @param application
     */
    public static void setDensity(@NonNull Application application) {
        //獲取application的DisplayMetrics
        appDisplayMetrics = application.getResources().getDisplayMetrics();
        //獲取狀態列高度
        barHeight = getStatusBarHeight(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() {
                }
            });
    }
}

/**
 * 此方法在BaseActivity中做初始化(如果不封裝BaseActivity的話,直接用下面那個方法就好)
 * 在setContentView()之前設定
 * @param activity
 */
public static void setDefault(Activity activity) {
    setAppOrientation(activity, WIDTH);
}

/**
 * 此方法用於在某一個Activity裡面更改適配的方向
 * 在setContentView()之前設定
 * @param activity
 * @param orientation
 */
public static void setOrientation(Activity activity, String orientation) {
    setAppOrientation(activity, orientation);
}

/**
 * targetDensity
 * targetScaledDensity
 * targetDensityDpi
 * 這三個引數是統一修改過後的值
 * orientation:方向值,傳入width或height
 */
private static void setAppOrientation(@Nullable Activity activity, String orientation) {

    float targetDensity;

    if (orientation.equals("height")) {
        targetDensity = (appDisplayMetrics.heightPixels - barHeight) / 667f;//設計圖的高度 單位:dp
    } else {
        targetDensity = appDisplayMetrics.widthPixels / 360f;//設計圖的寬度 單位:dp
    }

    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;
}

/**
 * 獲取狀態列高度
 *
 * @param context
 * @return
 */
public static int getStatusBarHeight(Context context) {
    int result = 0;
    int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = context.getResources().getDimensionPixelSize(resourceId);
    }
    return result;
    }
}

 

相關文章