1. 程式人生 > >Android劉海屏適配小結

Android劉海屏適配小結

一、關於劉海屏:

       Android 9 支援最新的全面屏,其中包含為攝像頭和揚聲器預留空間的螢幕缺口。 通過 DisplayCutout 類可確定非功能區域的位置和形狀,這些區域不應顯示內容。 要確定這些螢幕缺口區域是否存在及其位置,請使用 getDisplayCutout() 函式全新的窗口布局屬性 layoutInDisplayCutoutMode 讓您的應用可以為裝置螢幕缺口周圍的內容進行佈局。 您可以將此屬性設為下列值

二、主流國產機型(華為、小米、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;
    }
}