手机屏幕适配

2021-03-15  本文已影响0人  crossroads

前言

公司有很多要根据样式自动改变位置的需求,安卓机型各种各样,适配起来就是一个坑啊,今天把大致的坑填一下,供大家参考。

一坑:底部导航栏

一般手机我们会用这样的方法来判断有无导航栏

/**
     * @return 是否存在虚拟按键栏
     */
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public static boolean hasNavBar(Context context) {
        Resources res = context.getResources();
        int resourceId = res.getIdentifier("config_showNavigationBar", "bool", "android");
        if (resourceId != 0) {
            boolean hasNav = res.getBoolean(resourceId);
            String sNavBarOverride = getNavBarOverride();
            if ("1".equals(sNavBarOverride)) {
                hasNav = false;
            } else if ("0".equals(sNavBarOverride)) {
                hasNav = true;
            }
            return hasNav;
        } else {
            return !ViewConfiguration.get(context).hasPermanentMenuKey();
        }
    }

    /**
     * 判断虚拟按键栏是否重写
     */
    private static String getNavBarOverride() {
        String sNavBarOverride = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            try {
                Class c = Class.forName("android.os.SystemProperties");
                Method m = c.getDeclaredMethod("get", String.class);
                m.setAccessible(true);
                sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys");
            } catch (Exception e) {
                TRTCLogTools.e(TAG, e.toString());
            }
        }
        return sNavBarOverride;
    }

然而,会发现华为、小米、vivo不管有没有隐藏底部导航栏,它都返回true!所以只能针对这几个机型进行机型适配了。

  1. 首先判断手机机型
    /**
     * 获取手机品牌
     */
    public static String getDeviceManufacturer() {
        return android.os.Build.MANUFACTURER;
    }
    public static boolean isHuawei() {
        if ("HUAWEI".equalsIgnoreCase(getDeviceManufacturer())) {
            return true;
        }
        return false;
    }
  1. 根据不同手机判断有无底部导航栏

    public static boolean isXiaoMiNavigationBarShow(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            if (Settings.Global.getInt(context.getContentResolver(), "force_fsg_nav_bar", 0) != 0) {
                //开启手势,不显示虚拟键
                return false;
            }
        }
        return true;
    }

    public static boolean isHuaWeiNavigationBarShow(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            return Settings.System.getInt(context.getContentResolver(), "navigationbar_is_min", 0) == 0;
        } else {
            return Settings.Global.getInt(context.getContentResolver(), "navigationbar_is_min", 0) == 0;
        }
    }

    public static boolean isVivoNavigationBarShow(Context context) {
        return Settings.Secure.getInt(context.getContentResolver(), "navigation_gesture_on", 0) == 0;
    }

至此就可以判断是否有导航栏了。接下来,就可以获取导航栏高度了


    /**
     * 获取虚拟按键的高度
     */
    public static int getNavigationBarHeight(Context context) {
        int result = 0;
        if (hasNavBar(context)
                && (!isMIUI() || isXiaoMiNavigationBarShow(context))
                && (!isVivo() || isVivoNavigationBarShow(context))
                && (!isHuawei() || isHuaWeiNavigationBarShow(context))) {
            Resources res = context.getResources();
            int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");
            if (resourceId > 0) {
                result = res.getDimensionPixelSize(resourceId);
            }
        }
        return result;
    }

二坑:弹窗
场景:当做直播的时候,通常需要直播页面充满全屏,也就是要做沉浸式。这时,我们要设置页面全屏,使用android:windowTranslucentNavigation设置透明导航栏,然后发现有些手机show底部弹窗dialog底部永远在导航栏上方,而我们的activity的布局底部是在导航栏下方


灰色是activity底部,红色是弹窗底部

为了统一在导航栏上方,这时候就需要将activity的我们需要在虚拟导航栏之上的根布局使用

        android:fitsSystemWindows="true"

将布局底部也变为导航栏的上方,其实是设置了android:fitsSystemWindows="true"属性的view会自动添加一个值等于导航栏高度的paddingBottom。这样view的底部也就和dialog的底部保持一致啦。记住:不要在activity的根布局设置,因为如果你设置的话,它的顶部也不能到最上面啦。所以只要针对你想要至于导航栏之上的view的根布局就好。
三坑、手机屏幕高度
要做沉浸式,需要获取手机屏幕的真实高度,即包含导航栏这些的真正高度,要这样获取

    public static int getScreenRealHeight(Context context) {
        WindowManager windowManager =
                (WindowManager) context.getSystemService(Context.
                        WINDOW_SERVICE);
        final Display display = windowManager.getDefaultDisplay();
        Point outPoint = new Point();
        if (Build.VERSION.SDK_INT >= 19) {
            // 可能有虚拟按键的情况
            display.getRealSize(outPoint);
        } else {
            // 不可能有虚拟按键
            display.getSize(outPoint);
        }
        return outPoint.y;
    }

参考网址

底部导航栏适配
fitsystemwindow的分析

上一篇下一篇

猜你喜欢

热点阅读