Android 4.0+ 系统中SystemBars的适配问题

*以下关于获取Navigation Bar是否存在和如何获取高度参考自:
http://blog.csdn.net/lnb333666/article/details/41821149 Android 检查设备是否存在 导航栏 NavigationBar***

前不久做一个APP,需要在代码中对布局的高度进行设置,于是使用以下代码设置其高度:

//通过可视区域进行判断
Rect rect = new Rect();
this.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
ViewGroup.LayoutParams layoutParams;
layoutParams = new ViewGroup.LayoutParams(rect.width(), rect.height());

但是发现在魅族MX4上,应用最下面的部分总是被魅族系统定制的SmartBar挡住,虽然可以通过系统设置将SmartBar关闭,但这对用户来说不是一种很好的体验。
于是,在设置布局高度的时候,将代码中的高度参数设置为LayoutParams.MATCH_PARENT。 这样,就让布局高度自适应屏幕大小,SmartBar遮盖问题迎刃而解。

But!!!!
在Nexus6上,又出问题了。Nexus6上,LayoutParams.MATCH_PARENT高度要大于通过rect.height()获得的高度。
而这个高度,就是android 4.0加入的Navigation Bar的高度。但是,同样的设置,在Nexus4上是显示正常的。Nexus4是4.4的系统,Nexus6是5.0的系统。
总不能通过手机型号去一个个判断到底使用哪个高度吧?

其实,4.0的系统都添加了一个Navigation Bar的,任何设备运行自定义rom时都会设置一个选项,是否禁用的物理键,并添加一个导航栏。
参考API:ViewConfiguration.get(Context context).hasPermanentMenuKey() 的描述:Report if the device has a permanent menu key available to the user 和
android.view.KeyCharacterMap.deviceHasKey(int keyCode) 的描述:Queries the framework about whether any physical keys exist on the any keyboard attached to the device that are capable of producing the given key code。

通过上述描述可以发现,在4.0以上机型,我们可以通过判断屏幕外是否有返回键和菜单键,来判断当前设备是否存在Navigation Bar。如果物理菜单键和返回键都不存在的话,那就说明设备肯定有一个导航栏了。

代码如下:

 private boolean checkDeviceHasNavigationBar(Context activity) {
        //通过判断设备是否有返回键、菜单键(不是虚拟键,是手机屏幕外的按键)来确定是否有navigation bar
        boolean hasMenuKey = ViewConfiguration.get(activity)
                .hasPermanentMenuKey();
        boolean hasBackKey = KeyCharacterMap
                .deviceHasKey(KeyEvent.KEYCODE_BACK);

        if (!hasMenuKey && !hasBackKey) {
            return true;
        }
        return false;
    }

在参考博客中,作者还提供了一个获取导航键高度的代码:

private int getNavigationBarHeight(Activity activity) {  
        Resources resources = activity.getResources();  
        int resourceId = resources.getIdentifier("navigation_bar_height",  
                "dimen", "android");  
        //获取NavigationBar的高度  
        int height = resources.getDimensionPixelSize(resourceId);  
        return height;  
    }  

但这段代码无法通过高度 >0 判断是否有导航栏,在不同的设备4.0设备上,几乎都可以拿到设备的高度。不过是否可以获取到导航栏的高度。
如下结果为MI3获取到的高度:
这里写图片描述
MI3是看不到导航栏的,因为它有物理按键,但是通过代码仍然可以获取到它的Navigation Bar的高度。
因此,在获取设备高度的Navigation Bar高度的时候,一定要先判断当前设备是否存在Navigation Bar,然后再获取高度。

在不同设备中,获取设备是否存在Navigation Bar,打印信息如下:
Nexus4 :这里写图片描述
Nexus6:这里写图片描述
HUWEI MATE7:这里写图片描述
MX4:这里写图片描述

Nexus4和Nexus6都是存在导航栏的,而MATE7和MX4的导航栏是不可见的。MATE7和MX4显示的导航栏应该属于定制的控件,可能不属于Android系统默认的Navigation Bar

System Bars
The system bars are screen areas dedicated to the display of notifications, communication of device status, and device navigation. Typically the system bars are displayed concurrently with your app. Apps that display immersive content, such as movies or images, can temporarily hide the system bars to allow the user to enjoy full screen content without distraction.

这里写图片描述

System Bars包括两部分,见上图。

第一个称为 Status Bar
Displays pending notifications on the left and status, such as time, battery level, or signal strength, on the right. Swipe down from the status bar to show notification details.
第二个就是 Navigation Bar
New for phones in Android 4.0, the navigation bar is present only on devices that don’t have the traditional hardware keys. It houses the device navigation controls Back, Home, and Recents, and also displays a menu for apps written for Android 2.3 or earlier.

如果当前设备需要全屏显示,比如播放电影和图片,就需要将System Bars全部隐藏,使用

View decorView = getWindow().getDecorView();
// Hide both the navigation bar and the status bar.
// SYSTEM_UI_FLAG_FULLSCREEN is only available on Android 4.1 and higher, but as
// a general rule, you should design your app to hide the status bar whenever you
// hide the navigation bar.
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
              | View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);

Note the following:

  • With this approach, touching anywhere on the screen causes the
    navigation bar (and status bar) to reappear and remain visible. The
    user interaction causes the flags to be be cleared.
  • Once the flags have been cleared, your app needs to reset them if you
    want to hide the bars again. See Responding to UI Visibility Changes
    for a discussion of how to listen for UI visibility changes so that
    your app can respond accordingly.
  • Where you set the UI flags makes a difference. If you hide the system
    bars in your activity’s onCreate() method and the user presses Home,
    the system bars will reappear. When the user reopens the activity,
    onCreate() won’t get called, so the system bars will remain visible.
    If you want system UI changes to persist as the user navigates in and
    out of your activity, set UI flags in onResume() or
    onWindowFocusChanged().
  • The method setSystemUiVisibility() only has an effect if the view you
    call it from is visible.
  • Navigating away from the view causes flags set with
    setSystemUiVisibility() to be cleared.

从上面提示可以看出,隐藏System Bars之后,触摸屏幕任何部分,都会令System Bars重新显示。
因此我们可以通过监听系统UI的显示变化,来做我们想做的事情。

View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener
        (new View.OnSystemUiVisibilityChangeListener() {
    @Override
    public void onSystemUiVisibilityChange(int visibility) {
        // Note that system bars will only be "visible" if none of the
        // LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
        if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
            // TODO: The system bars are visible. Make any desired
            // adjustments to your UI, such as showing the action bar or
            // other navigational controls.
        } else {
            // TODO: The system bars are NOT visible. Make any desired
            // adjustments to your UI, such as hiding the action bar or
            // other navigational controls.
        }
    }
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值