一种极地成本的适配方案,本人已经在现在的项目中实践,没有出现明显适配异常
ScreenUtil.adaptDensity(this, 360, 604, true, ScreenUtil.MODE_FORCE_ADAPT_SHORT_SIDE);
在Application的onCreate中添加一行这样的代码
public class ScreenUtil {
public static final int MODE_ADAPT_TWO_SIDE = 1;
public static final int MODE_FORCE_ADAPT_SHORT_SIDE = 2;
public static final int MODE_FORCE_ADAPT_LONG_SIDE = 3;
private static int screenHeightWithPx = 0;
private static int screenWidthWithPx = 0;
private static float systemDensityRatio = 0;
private static float adaptDensityRatio = 0;
private static DisplayMetrics displayMetrics;
private static LinkedList<Activity> activityLinkedList = new LinkedList<>();
/**
* 获取屏幕宽度
*
* @return
*/
public static int getWidth() {
return screenWidthWithPx;
}
/**
* 获取屏幕高度
*
* @return
*/
public static int getHeight() {
return screenHeightWithPx;
}
private static boolean webViewHasDestroyed = false;
/**
* 最小宽度适配 phone、tablet、tv;
* 1.实现了与设计稿不同比例设备的兼容; e.g. 设计比例:16:9 设备比例 4:3 按照16:9显示 但是直接造成缺陷:不能充分使用屏幕像素;
* 2.支持minSdkVersion>=17;
*
* @param application {@link android.app.Application or it's subClass}
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
public static void adaptDensity(final Application application, final int shortSideLengthWidthDp, final int longSideLengthWithDp, final boolean isSetFontSizeToDefault, final int adaptMode) {
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration config) {
Resources resources = application.getResources();
updateConfig(application, resources, isSetFontSizeToDefault);
}
@Override
public void onLowMemory() {
}
});
if (Build.VERSION.SDK_INT >= 26) {
application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
activityLinkedList.add(activity);
Resources resources = activity.getResources();
updateConfig(activity, resources, isSetFontSizeToDefault);
}
@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) {
activityLinkedList.remove(activity);
}
});
}
//设计稿宽高比
float aspectRatio = longSideLengthWithDp / (float) shortSideLengthWidthDp;
Resources resources = application.getResources();
Configuration configuration = resources.getConfiguration();
displayMetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) application.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getRealMetrics(displayMetrics);
//屏幕物理高 px
screenHeightWithPx = displayMetrics.heightPixels;
//屏幕物理宽 px
screenWidthWithPx = displayMetrics.widthPixels;
Log.d("adaptDensity", "screenHeightWithPx =" + screenHeightWithPx);
Log.d("adaptDensity", "screenWidthWithPx =" + screenWidthWithPx);
//屏幕最小宽度 px
int screenSwWithPx;
//屏幕长边 px
int screenLongSideLengthWithPx;
if (screenHeightWithPx > screenWidthWithPx) {
screenSwWithPx = screenWidthWithPx;
screenLongSideLengthWithPx = screenHeightWithPx;
} else {
screenSwWithPx = screenHeightWithPx;
screenLongSideLengthWithPx = screenWidthWithPx;
}
Log.d("adaptDensity", "screenSwWithPx =" + screenSwWithPx);
Log.d("adaptDensity", "screenLongSideLengthWithPx =" + screenLongSideLengthWithPx);
//屏幕最小宽度 dp
int screenSwWithDp = configuration.smallestScreenWidthDp;
//屏幕密度比
systemDensityRatio = displayMetrics.density;
Log.d("adaptDensity", "screenSwWithDp =" + screenSwWithDp);
Log.d("adaptDensity", "systemDensityRatio =" + systemDensityRatio);
int adaptSwWithDp;
int adaptLongSideLengthWithDp;
adaptSwWithDp = screenSwWithDp;
adaptLongSideLengthWithDp = (int) (adaptSwWithDp * aspectRatio);
Log.d("adaptDensity", "adaptSwWithDp =" + adaptSwWithDp);
Log.d("adaptDensity", "adaptLongSideLengthWithDp =" + adaptLongSideLengthWithDp);
if (adaptMode == MODE_ADAPT_TWO_SIDE) {
float ratio1 = systemDensityRatio;
float ratio2 = screenLongSideLengthWithPx / (float) adaptLongSideLengthWithDp;
adaptDensityRatio = ratio1 > ratio2 ? ratio2 : ratio1;
} else if (adaptMode == MODE_FORCE_ADAPT_SHORT_SIDE) {
adaptDensityRatio = systemDensityRatio;
} else if (adaptMode == MODE_FORCE_ADAPT_LONG_SIDE) {
adaptDensityRatio = screenLongSideLengthWithPx / (float) adaptLongSideLengthWithDp;
}
adaptDensityRatio *= screenSwWithDp / (float) shortSideLengthWidthDp;
Log.d("adaptDensity", "update systemDensityRatio " + systemDensityRatio + " ==> " + adaptDensityRatio);
updateConfig(application, resources, isSetFontSizeToDefault);
}
private static void destroyWebView(Context context) {
try {//Caused by android.webkit.WebViewFactory$MissingWebViewPackageException
new WebView(context).destroy();//see https://stackoverflow.com/questions/40398528/android-webview-language-changes-abruptly-on-android-n
webViewHasDestroyed = true;
} catch (Exception e) {
e.printStackTrace();
}
}
private static void updateConfig(Context context, Resources resources, boolean isSetFontSizeToDefault) {
if (!webViewHasDestroyed) {
destroyWebView(context);
}
Configuration newConfig = resources.getConfiguration();
newConfig.densityDpi = (int) (adaptDensityRatio * DisplayMetrics.DENSITY_DEFAULT);
if (isSetFontSizeToDefault) {
newConfig.fontScale = 1;
}
resources.updateConfiguration(newConfig, displayMetrics);
}
/**
* dip2px
*
* @param context
* @param dpValue
* @return
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* px2dip
*
* @param context
* @return
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* px2sp
*
* @param context
* @return
*/
public static int px2sp(Context context, float pxValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
/**
* sp2px
*
* @param spValue
* @return
*/
public static int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
/**
* 获得状态栏的高度
*
* @param context
* @return
*/
public static int getStatusHeight(Context context) {
int statusHeight = -1;
try {
Class clazz = Class.forName("com.android.internal.R$dimen");
int height = Integer.parseInt(clazz.getField("status_bar_height")
.get(null).toString());
statusHeight = context.getResources().getDimensionPixelSize(height);
statusHeight = recoverToSystemValueIfNeed(statusHeight);
} catch (Exception e) {
e.printStackTrace();
}
return statusHeight;
}
private static int recoverToSystemValueIfNeed(int valueWithPx) {
if (systemDensityRatio != adaptDensityRatio) {
valueWithPx = (int) (valueWithPx / adaptDensityRatio * systemDensityRatio);
}
return valueWithPx;
}
}