Android中沉浸式状态栏的应用

在Android5.0版本后,谷歌公司为Android系统加入了很多新特性,刷新了Android用户的体验度。而其中的一个新特性就是沉浸式状态栏。那么问题来了,很多非移动端的小伙伴就要问了,什么是沉浸式状态栏?传统的手机状态栏是呈现出黑色条状的,有的和手机主界面有很明显的区别。这样就在一定程度上牺牲了视觉宽度,界面面积变小。而沉浸式状态栏将状态栏的颜色变为透明,并将原有的布局沾满了手机屏幕,使得状态栏和手机布局内容融为一体。下面,我们来详细的说明沉浸式状态栏在项目中的实际应用。

要在当前的Activity界面实现沉浸式,首先我们要在oncreate方法中写入如下代码:

getWindow().requestFeature(Window.FEATURE_NO_TITLE);
Window window = getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
   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_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
   window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
   window.setStatusBarColor(Color.TRANSPARENT);
   window.setNavigationBarColor(Color.TRANSPARENT);
}

这样代码就可以实现沉浸式状态。由于沉浸式状态栏只支持5.0以上手机,所以我们在这里进行了版本判断。不过实际操作中,有小伙伴又遇到了新的问题。有些有虚拟按键的也被沉浸了,这个就会很郁闷了。我们的构思是布局中有一个黑色的view,在有虚拟按键的手机上显示出来,并且高度与虚拟按键一致。具体操作如下。

检查是否具有虚拟按键

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);
            // check override flag
            String sNavBarOverride = getNavBarOverride();
            if ("1".equals(sNavBarOverride)) {
                hasNav = false;
            } else if ("0".equals(sNavBarOverride)) {
                hasNav = true;
            }
            return hasNav;
        } else { // fallback
            if (Build.VERSION.SDK_INT >= 14) {
                return !ViewConfiguration.get(context).hasPermanentMenuKey();
            } else {
                return false;
            }
        }
    }

判断虚拟按键栏是否重写

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 (Throwable e) {
            }
        }
        return sNavBarOverride;
    }

获取虚拟按键栏高度

public static int getBottomStatusHeight(Context context) {
        int totalHeight = getDpi(context);

        int contentHeight = getScreenHeight(context);

        return totalHeight - contentHeight;
    }

获取屏幕高度

 public static int getScreenHeight(Context context) {
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.heightPixels;
    }
获取屏幕原始尺寸高度,包括虚拟功能键高度
public static int getDpi(Context context) {
        int dpi = 0;
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = windowManager.getDefaultDisplay();
        DisplayMetrics displayMetrics = new DisplayMetrics();
        @SuppressWarnings("rawtypes")
        Class c;
        try {
            c = Class.forName("android.view.Display");
            @SuppressWarnings("unchecked")
            Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
            method.invoke(display, displayMetrics);
            dpi = displayMetrics.heightPixels;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dpi;
    }

代码中设置布局中View的高度

if (hasNavBar(this)) {
            bottomView.getViewTreeObserver().addOnGlobalLayoutListener(
                    new ViewTreeObserver.OnGlobalLayoutListener() {
                        // 当layout执行结束后回调此方法
                        @Override
                        public void onGlobalLayout() {
                            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) bottomView.getLayoutParams();
                            params.height = getBottomStatusHeight(ActivityShopIndex.this);
                            bottomView.setLayoutParams(params);
                            bottomView.setVisibility(View.VISIBLE);
                        }
                    });
        }

这样我们就成功将虚拟按键栏也被沉浸的问题解决了。

作者 水木

posted @ 2017-10-31 15:39  WidgetBox  阅读(435)  评论(0编辑  收藏  举报