天天看點

Android 劉海、挖孔、水滴螢幕的狀态高度擷取與适配

一般需要處理狀态欄的問題都是适配問題,适配就稍微有點麻煩,比如:劉海屏,水滴屏、以及剛剛不久出的挖孔屏等這類都屬于劉海屏範圍内,适配的話就要在各大廠商做處理了,比如華為:剛剛開始以為隻需判斷是否是劉海屏就好了,設定一個狀态欄高度就好Ok了,結果不然:

狀态欄高度:

private fun setStatusHeight() {
        val layoutParams = base_head.layoutParams as LinearLayout.LayoutParams
        layoutParams.setMargins(0,StatusBarUtils.getStatusBarHeight(mContext),0,0)
        base_head.layoutParams = layoutParams
    }
           
/**
     * 獲得通知欄高度
     */
    public static int getStatusBarHeight(Context context) {
        Class<?> c = null;
        Object obj = null;
        Field field = null;
        int x = 0, statusBarHeight = 0;
        try {
            c = Class.forName("com.android.internal.R$dimen");
            obj = c.newInstance();
            field = c.getField("status_bar_height");
            x = Integer.parseInt(field.get(obj).toString());
            statusBarHeight = context.getResources().getDimensionPixelSize(x);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return statusBarHeight;
    }
           

因為這裡設定的是鋪滿全屏,需要重新計算狀态欄高度,在小米、oppo、華為的劉海屏和水滴螢幕沒有問題,但在華為的挖孔屏上出現問題,就是常見的重疊,其他品牌的手機因為沒有,不知道有沒有出現類似的問題,先說問題原因是:華為的狀态欄高度是擷取到了的值很小,隻有26仔細看到話在挖孔的上面很小的空白處是有高度的那個就是狀态欄高度,導緻出現重疊的原因,解決方法就是擷取挖孔的高度,把值設定進去就好了;

/**
     * 擷取華為劉海的高
     *
     * @param context
     * @return
     */
    public static int getNotchSizeAtHuawei(Context context) {
        int[] ret = new int[]{0, 0};
        try {
            ClassLoader cl = context.getClassLoader();
            Class<?> HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
            Method get = HwNotchSizeUtil.getMethod("getNotchSize");
            ret = (int[]) get.invoke(HwNotchSizeUtil);

        } catch (ClassNotFoundException e) {
            Log.e("NotchScreenUtil", "getNotchSize ClassNotFoundException");
        } catch (NoSuchMethodException e) {
            Log.e("NotchScreenUtil", "getNotchSize NoSuchMethodException");
        } catch (Exception e) {
            Log.e("NotchScreenUtil", "getNotchSize Exception");
        }
        return ret[1];
    }
           

這個是專門針對華為過去的高度,其他品牌擷取的值為0,現在隻适配了這些後期有問題會補上。

/**
     * 是否有劉海屏
     *
     * @return
     */
    public static boolean hasNotchInScreen(Activity activity) {
        // android  P 以上有标準 API 來判斷是否有劉海屏
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            View decorView = activity.getWindow().getDecorView();
            WindowInsets windowInsets = decorView.getRootWindowInsets();
            if (windowInsets != null) {
                DisplayCutout displayCutout = windowInsets.getDisplayCutout();
                if (displayCutout != null) {
                    List<Rect> rects = displayCutout.getBoundingRects();

                    for (Rect rect : rects) {
                        Log.e("notch", "cutout.getSafeInsetTop():" + displayCutout.getSafeInsetTop()
                                + ", cutout.getSafeInsetBottom():" + displayCutout.getSafeInsetBottom()
                                + ", cutout.getSafeInsetLeft():" + displayCutout.getSafeInsetLeft()
                                + ", cutout.getSafeInsetRight():" + displayCutout.getSafeInsetRight()
                                + ", cutout.rects:" + rect
                        );
                    }

                    int screenTopMargin = displayCutout.getSafeInsetTop();
                    int screenBottomMargin = displayCutout.getSafeInsetBottom();

                    //通過判斷是否存在rects來确定是否劉海屏手機
                    if (rects.size() > 0) {
                        return true;
                    }
                }
            }
        }
        // 通過其他方式判斷是否有劉海屏  目前官方提供有開發文檔的就 小米,vivo,華為(榮耀),oppo
        String manufacturer = Build.MANUFACTURER;
        if (StringUtils.isEmpty(manufacturer)) {
            return false;
        } else if (manufacturer.equalsIgnoreCase("HUAWEI")) {
            return hasNotchHw(activity);
        } else if (manufacturer.equalsIgnoreCase("xiaomi")) {
            return hasNotchXiaoMi(activity);
        } else if(manufacturer.equalsIgnoreCase("oppo")||manufacturer.equalsIgnoreCase("realme")) {//這裡是除oppo以外的品牌手機,這裡暫時沒有這個手機,但也加上是評論區的夥伴驗證的
            return hasNotchOPPO(activity);
        } else if (manufacturer.equalsIgnoreCase("vivo")) {
            return hasNotchVIVO(activity);
        } else {
            return false;
        }
    }

    /**
     * 擷取華為劉海的高
     *
     * @param context
     * @return
     */
    public static int getNotchSizeAtHuawei(Context context) {
        int[] ret = new int[]{0, 0};
        try {
            ClassLoader cl = context.getClassLoader();
            Class<?> HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
            Method get = HwNotchSizeUtil.getMethod("getNotchSize");
            ret = (int[]) get.invoke(HwNotchSizeUtil);

        } catch (ClassNotFoundException e) {
            Log.e("NotchScreenUtil", "getNotchSize ClassNotFoundException");
        } catch (NoSuchMethodException e) {
            Log.e("NotchScreenUtil", "getNotchSize NoSuchMethodException");
        } catch (Exception e) {
            Log.e("NotchScreenUtil", "getNotchSize Exception");
        }
        return ret[1];
    }


    /**
     * 判斷vivo是否有劉海屏
     * https://swsdl.vivo.com.cn/appstore/developer/uploadfile/20180328/20180328152252602.pdf
     *
     * @param activity
     * @return
     */
    private static boolean hasNotchVIVO(Activity activity) {
        try {
            @SuppressLint("PrivateApi") Class<?> c = Class.forName("android.util.FtFeature");
            Method get = c.getMethod("isFeatureSupport", int.class);
            return (boolean) (get.invoke(c, 0x20));
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 判斷oppo是否有劉海屏
     * https://open.oppomobile.com/wiki/doc#id=10159
     *
     * @param activity
     * @return
     */
    private static boolean hasNotchOPPO(Activity activity) {
        return activity.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
    }

    /**
     * 判斷xiaomi是否有劉海屏
     * https://dev.mi.com/console/doc/detail?pId=1293
     *
     * @param activity
     * @return
     */
    private static boolean hasNotchXiaoMi(Activity activity) {
        try {
            @SuppressLint("PrivateApi") Class<?> c = Class.forName("android.os.SystemProperties");
            Method get = c.getMethod("getInt", String.class, int.class);
            return (int) (get.invoke(c, "ro.miui.notch", 0)) == 1;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 判斷華為是否有劉海屏
     * https://devcenter-test.huawei.com/consumer/cn/devservice/doc/50114
     *
     * @param activity
     * @return
     */
    private static boolean hasNotchHw(Activity activity) {

        try {
            ClassLoader cl = activity.getClassLoader();
            Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
            Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");
            return (boolean) get.invoke(HwNotchSizeUtil);
        } catch (Exception e) {
            return false;
        }
    }