[Android]今日頭條的螢幕適配方案,簡單又粗暴!
有個大佬以今日頭條的方案為基礎,結合自己的開發經驗,封裝了一個螢幕適配庫,有興趣的可以瞭解一下.
我先簡單說一下這個方案的思路,它是通過修改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;
}
}
相關文章
- android 今日頭條的螢幕適配理解Android
- Flutter螢幕適配,簡單粗暴的全域性適配方式Flutter
- 今日頭條螢幕適配方案終極版:極低成本 Android 適配方案!Android
- android 螢幕適配Android
- 今日頭條螢幕適配方案終極版正式釋出!
- 極其簡單的Flutter 螢幕適配Flutter
- 騷年你的螢幕適配方式該升級了!-今日頭條適配方案
- Android 螢幕適配:最全面的解決方案Android
- Android 主流螢幕以及適配Android
- Android螢幕適配方案Android
- Android螢幕適配(理論適配100%機型)Android
- Android 螢幕適配終結者Android
- Android 螢幕適配從未如斯簡單(已廢棄該使用方式)Android
- 螢幕適配
- android螢幕適配三:通過畫素密度適配Android
- Android螢幕適配方案分析Android
- Android螢幕適配總結和思考Android
- Android技能樹 — 螢幕適配小結Android
- Android螢幕適配很麻煩嗎?不!太簡單了。。。(持續更新)Android
- AutoLayout螢幕適配
- Flutter螢幕適配Flutter
- 淺談-web螢幕適配的解決方案Web
- Android螢幕適配前先了解這些Android
- android 螢幕適配一:通過自定義View的方式實現適配AndroidView
- Android最全螢幕適配的幾個重要概念(三)Android
- flutter 螢幕尺寸適配 字型大小適配Flutter
- Android dp方式的螢幕適配工具使用(Android Studio外掛方式)Android
- android 螢幕適配二:手寫百分比佈局適配Android
- 頭條螢幕適配問題彙總及解決,這次你值得嘗試
- 移動APP測試-Android螢幕適配問題(一)APPAndroid
- 移動APP測試:Android螢幕適配問題二APPAndroid
- android螢幕適配方法Android
- Android 螢幕自適應Android
- @media 移動端螢幕適配
- 【postcss-px-to-viewport】螢幕適配CSSView
- Flutter螢幕適配 - 等比縮放Flutter
- Android螢幕適配很難嘛?其實也就那麼回事Android
- 移動 web 端螢幕適配 – remWebREM