适配缘起
由于Android各种机型屏幕尺寸众多及屏幕分辨率各异的原因,很容易出现同一元素在不同手机上显示效果不同的问题。所以为了让用户获得一致的用户体验效果,使得某一元素在Android不同尺寸、不同分辨率的、不同系统的手机上保持界面上的效果一致,我们需要对各种手机屏幕进行适配!
基本概念
1 2 3 4 5 6
| px = dp * density density = DPI / 160
此方案需要水平和竖直方向分别适配: density = 当前设备屏幕总宽度(单位为像素)/ 设计图总宽度(单位为 dp) density = 当前设备屏幕总高度(单位为像素)/ 设计图总高度(单位为 dp)
|
PS:和 density 相关的还有 densityDpi、scaledDensity,我们根据 density 等比修改 densityDpi、scaledDensity
具体使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| @Override public void initData(@Nullable Bundle bundle) { if (ScreenUtils.isPortrait()) { ScreenUtils.adaptScreen4VerticalSlide(this, 360); } else { ScreenUtils.adaptScreen4HorizontalSlide(this, 360); } }
/** * Adapt the screen for horizontal slide. * * @param activity The activity. * @param designHeightInPx The size of design diagram's height, in pixel. */ public static void adaptScreen4HorizontalSlide(final Activity activity, final int designHeightInPx) { adaptScreen(activity, designHeightInPx, false); } /** * Reference from: https://mp.weixin.qq.com/s/d9QCoBP6kV9VSWvVldVVwA */ private static void adaptScreen(final Activity activity, final int sizeInPx, final boolean isVerticalSlide) { final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics(); final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics(); final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics(); if (isVerticalSlide) { activityDm.density = activityDm.widthPixels / (float) sizeInPx; } else { activityDm.density = activityDm.heightPixels / (float) sizeInPx; } activityDm.scaledDensity = activityDm.density * (systemDm.scaledDensity / systemDm.dens activityDm.densityDpi = (int)(160 * activityDm.density); appDm.density = activityDm.density; appDm.scaledDensity = activityDm.scaledDensity; appDm.densityDpi = activityDm.densityDpi; } /** * Cancel adapt the screen. * * @param activity The activity. */ public static void cancelAdaptScreen(final Activity activity) { final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics(); final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics(); final DisplayMetrics activityDm = activity.getResources().getDisplayMetrics(); activityDm.density = systemDm.density; activityDm.scaledDensity = systemDm.scaledDensity; activityDm.densityDpi = systemDm.densityDpi; appDm.density = systemDm.density; appDm.scaledDensity = systemDm.scaledDensity; appDm.densityDpi = systemDm.densityDpi; } /** * Return whether adapt screen. * * @return {@code true}: yes<br>{@code false}: no */ public static boolean isAdaptScreen() { final DisplayMetrics systemDm = Resources.getSystem().getDisplayMetrics(); final DisplayMetrics appDm = Utils.getApp().getResources().getDisplayMetrics(); return systemDm.density != appDm.density; }
|
ScreenUtils.java
屏幕适配问题汇总及解决
webview 加载后发现 density 复原?
由于 WebView 初始化的时候会还原 density 的值导致适配失效,继承 WebView,重写如下方法:
1 2 3 4 5
| @Override public void setOverScrollMode(int mode) { super.setOverScrollMode(mode); ScreenUtils.restoreAdaptScreen(); }
|
如何让系统 View 尺寸正常?
后面提到的 Dialog 和 Toast 其实都可以用用这种解决方案,就是在 inflate 相关 View 之前调用 ScreenUtils#cancelAdaptScreen,show 之后调用 ScreenUtils#restoreAdaptScreen 即可,这样就可以让系统 View 显示正常尺寸。