Android劉海屏適配小結
阿新 • • 發佈:2019-01-08
一、關於劉海屏:
Android 9 支援最新的全面屏,其中包含為攝像頭和揚聲器預留空間的螢幕缺口。 通過 DisplayCutout
類可確定非功能區域的位置和形狀,這些區域不應顯示內容。 要確定這些螢幕缺口區域是否存在及其位置,請使用 getDisplayCutout()
函式全新的窗口布局屬性 layoutInDisplayCutoutMode
讓您的應用可以為裝置螢幕缺口周圍的內容進行佈局。 您可以將此屬性設為下列值
LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
二、主流國產機型(華為、小米、vivo、oppo)適配方案
/** *華為手機判斷是否有劉海屏 */ private boolean hasNotchAtHuaWei(Context context) { boolean ret = false; try { ClassLoader classLoader = context.getClassLoader(); Class cl = classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil"); Method get = cl.getMethod("hasNotchInScreen"); ret = (boolean) get.invoke(cl); } catch (ClassNotFoundException e) { Log.e("MyLog", "hasNotchAtHuawei ClassNotFoundException"); } catch (NoSuchMethodException e) { Log.e("MyLog", "hasNotchAtHuawei NoSuchMethodException"); } catch (Exception e) { Log.e("MyLog", "hasNotchAtHuawei Exception"); } return ret; } /** * 獲取華為手機劉海的尺寸 * @return 寬高 px */ private int[] getNotchSizeAtHuawei(Context context) { int[] ret = new int[]{0, 0}; try { ClassLoader cl = context.getClassLoader(); Class sizeUtils = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil"); Method get = sizeUtils.getMethod("getNotchSize"); ret = (int[]) get.invoke(sizeUtils); } catch (ClassNotFoundException e) { Log.i("MyLog", "getNotchSizeAtHuawei ClassNotFoundException"); } catch (NoSuchMethodException e) { Log.i("MyLog", "getNotchSizeAtHuawei NoSuchMethodException"); } catch (Exception e) { Log.i("MyLog", "getNotchSizeAtHuawei Exception"); } return ret; } /** * vivo手機 判斷是否有劉海屏 * vivo不提供介面獲取劉海尺寸,目前vivo的劉海寬為100dp,高為27dp。(100dp x 27dp) */ private static boolean hasNotchAtVivo(Context context) { boolean ret = false; try { ClassLoader classLoader = context.getClassLoader(); Class feature = classLoader.loadClass("android.util.FtFeature"); Method method = feature.getMethod("isFeatureSupport", int.class); ret = (boolean) method.invoke(feature, VIVO_NOTCH); } catch (ClassNotFoundException e) { Log.e("MyLog", "hasNotchAtVivo ClassNotFoundException"); } catch (NoSuchMethodException e) { Log.e("MyLog", "hasNotchAtVivo NoSuchMethodException"); } catch (Exception e) { Log.e("MyLog", "hasNotchAtVivo Exception"); } return ret; } /** * OPPO 是否有劉海屏 * 顯示屏寬度為1080px,高度為2280px。劉海區域則都是寬度為324px, 高度為80px。 */ private boolean hasNotchAtOPPO(Context context) { return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism"); } /** * 小米手機獲取劉海高度 */ private int getXiaoMiCutH(Context context) { int resourceId = context.getResources().getIdentifier("notch_height", "dimen", "android"); int result = 0; if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); } return result; } /** * 獲取劉海高度 */ public int adaptation() { int cutHeight = 0; if (Constant.FinalVar.HUAI_WEI.equalsIgnoreCase(Constant.Variable.carrier)) { if (hasNotchAtHuaWei(mContext)) { cutHeight=getNotchSizeAtHuawei(mContext)[1]; } } else if (Constant.FinalVar.XIAO_MI.equalsIgnoreCase(Constant.Variable.carrier)) {if (SystemPropertiesUtils.getInt("ro.miui.notch", 0) == 1) { cutHeight = getXiaoMiCutH(mContext); } } else if (Constant.FinalVar.VIVO.equalsIgnoreCase(Constant.Variable.carrier)) { if (hasNotchAtVivo(mContext)) { cutHeight = DpPxUtils.dip2px(mContext,27); } } else if (Constant.FinalVar.OPPO.equalsIgnoreCase(Constant.Variable.carrier)) { if (hasNotchAtOPPO(mContext)) { cutHeight =80; } } return cutHeight; } /** * 設定狀態列透明 */ public void initStateBar() { Window window = ((Activity) mContext).getWindow(); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); int cutHeight=adaptation(); if (cutHeight>0){ window.setStatusBarColor(Color.BLACK); }else { window.setStatusBarColor(Color.TRANSPARENT); window.setNavigationBarColor(Color.TRANSPARENT); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ if (cutHeight==0){ try { @SuppressLint("PrivateApi") Class decorViewClazz = Class.forName("com.android.internal.policy.DecorView"); Field field = decorViewClazz.getDeclaredField("mSemiTransparentStatusBarColor"); field.setAccessible(true); field.setInt(window.getDecorView(), Color.TRANSPARENT); } catch (Exception e) { e.printStackTrace(); } } } } 在BaseActivity通用設定,給跟佈局設定一個劉海高度的paddingtop if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { int cutHeight=densityUtil.adaptation(); if (cutHeight > 0) { ViewGroup vg = ((Activity) mContext).findViewById(android.R.id.content); vg.setPadding(0, cutHeight, 0, 0); } }
小米手機判斷是否有劉海缺口的工具類
public class SystemPropertiesUtils { public static int getInt(String s, int i) { int res = 0; try { Class<?> aClass = Class.forName("android.os.SystemProperties"); Method[] declaredMethods = aClass.getDeclaredMethods(); Method temp = null; for(Method m:declaredMethods){ if ("getInt".equals(m.getName())){ temp=m; break; } } if (temp!=null){ res = (int) temp.invoke(null,s, i); } /// Method method = aClass.getMethod("getInt", String.class, Integer.class); } catch (InvocationTargetException | IllegalAccessException e) { e.printStackTrace(); Log.i("MyLog",">>>>>>>>>>>SystemPropertiesUtils="+e.toString()); } catch (ClassNotFoundException e) { e.printStackTrace(); Log.i("MyLog",">>>>>>>>>>>SystemPropertiesUtils="+e.toString()); } return res; } }