如何让程序在Nexus上全屏显示

这可能是我最短的一篇博客了哈 哈 哈~ 魂淡,填完坑后,就不是最短的一篇博客了。。。。。。

图片来源 http://www.pcpop.com/view/1/1157/1157137_1.shtml?r=09092235

从网上盗的一张Nexus 6P运行程序的截图,是不是看起来还是不错,但是有个问题就是底部的 Navigation Bar ,尤其如果是在游戏界面,这个东西还是一直存在,导致游戏不能全屏,太影响观感了。手游基本上都是全屏的,这个不能忍,必须干掉。

犹记得4.0刚来的时候,这个黑条就出现了,一直霸占着屏幕底部,那时无能无力,后来估计Google也意识到这个黑条过于嚣张了,该是治治的时候了,于是乎就给出了解决方案,咱们可以隐藏这个黑条了。

解决方法如下,在onCreate里或者游戏程序开始时调用一下下面的这个方法就行了。

private void hideSystemUI(){
        View decorView = getWindow().getDecorView();

        int uiOptions =  View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;

        decorView.setSystemUiVisibility(uiOptions);
    }

在程序开始的时候调用这个方法,然后就会看到程序界面是全屏的,此时 Navigation Bar和Status Bar都是消失不可见的,如果此时想退出游戏,只需从屏幕顶部或者底部向屏幕里轻滑一下,轻滑后Navigation Bar和Status Bar就会以半透明状态出现,然后等待一会就会自动消失,这样就满足了我们的需求了。这段程序在Nexus6P上测试过,没有问题。

如果想知道这个方法的原理以及里面参数的作用,请去查看博客最后的参考文章。

方法局限:

SYSTEM_UI_FLAG_IMMERSIVE_STICKY

上面这个参数是从Android 4.4 (API Level 19)开始加上的,然后结果就是4.4之前的系统还未测试过,不过可以去参考下面参考文章里的最后一篇文章,加一个监听器,监听 sysui的显示状态,然后再做显示或者隐藏处理。


1.游戏以全屏状态显示,没有Navigation Bar和Status Bar。

2.要使用Android系统的返回键时,从顶部或者底部向屏幕内滑动一下,就可以看到Navigation Bar和Status Bar,你可以点击返回按钮退出游戏,也可以看时间。

3.滑出Navigation后,过一会儿Navigation Bar会自动隐藏,这样就可以继续全屏玩游戏了,不影响游戏观感。


参考文章:

http://developer.android.com/intl/zh-cn/training/system-ui/status.html

http://developer.android.com/intl/zh-cn/training/system-ui/navigation.html

http://developer.android.com/intl/zh-cn/training/system-ui/immersive.html

http://developer.android.com/training/system-ui/visibility.html

以上文章需要翻墙才可以看,如果翻墙有问题的话也可以去你本机android sdk目录中的Docs中找到,文章所在目录是 docs/training/system-ui/


---------------------------------------------------------------------------------------------------填坑分割线-------------------------------------------------------------------------------------------------------------

功能实现了,但是有bug,下面是填坑内容;

坑1---------运行程序状态,点击Home键回到主页,然后再返回程序,黑条会出现,而且不会消失。

出现这个的原因是,程序从后台再回到前台时,Activity onRestart了,而我们的hideSystemUI是写在onCreate里的,onRestart时不会调用onCreate,所以Activity重新开启后,这个系统黑条又出现了。

解决方案:将 hideSystemUI写到 onResume 方法里,因为程序第一次启动以及从后台返回到前台时都会调用这个方法,这样就可以再次隐藏系统黑条了。


坑2-----------出现此坑需要满足的条件

1.Moto X2机子,因为目前真机只有Nexus6和MotoX2,但是Nexus6不会出现此坑,所以先让MotoX2背这个锅,也或许你们不会遇到。

2.设置手机屏幕锁定方式为滑动。

3.程序运行状态,并且划出了半透明的黑条。

4.快速按关机键锁屏接着开屏,要快速 ->_->


好,按上面步骤完成后,此时上划开屏,你会发现黑条又出现了,onResume 那个方式失效了。

出现这个情况的原因应该是黑条出现的时机晚于 onResume的运行。不过Nexus6不会出现这种情况,略坑。然后Nexus6和MotoX2两个机子还有一个区别就是系统版本,Nexus6是6.0,而MotoX2的是5.1,不知道是不是和系统版本有关。

解决方案:因为Activity的创建虽然会经过onResume,onStart等等这些阶段,但是Activity最终创建初始化结束,呈现到手机界面上,却不是在这几个阶段中,最终阶段可以在 onWindowFocusChanged 这个方法中判断,即在窗口得到焦点后,可以表明Activity整个初始化完毕了。关于这个方法详情可以参考这个文章http://blog.csdn.net/pi9nc/article/details/9237031。

所以可以在Activity里实现这个方法,然后将hideSystemUI方法写到里面。记得方法里要调用父类的onWindowFocusChanged,即

super.onWindowFocusChanged,否则会出现黑屏bug。

 

坑3-----------当程序中有 EditText组件或者其他可以呼出虚拟键盘的组件,当呼出虚拟键盘时黑条也会跟着一起出现,但是当你输入完文字,点击完成或者返回键隐藏虚拟键盘后,你就会发现黑条却坚挺的留在那里,系统的status bar也会存在,坑爹呀!!!

坑3填坑过程,之所以坑3排在最后是因为这个真的很坑,然后为了填坑,我先是研究了如何判断虚拟键盘的显示和隐藏,然后又研究了虚拟键盘按键事件。关于如何判断虚拟键盘的显示和隐藏,网上找了许久也没有满意的答案,因为这个虚拟键盘有两种显示状态,一种是在竖屏状态,一种是在横屏状态,横屏状态默认是全屏显示的,网上那个计算layout尺寸的过于麻烦且不适用横屏情况。

然后关于检测按键事件这个,如果你的程序是横屏模式,默认显示的虚拟键盘是全屏显示的话,就可以在Activity里实现onKeyUp方法,然后通过判断点击完成按键事件,进而调用hideSystemUI方法。因为横屏全屏键盘,会存在一个完成按钮(如下图示例),点击这个按钮后虚拟键盘就会自动隐藏,这个按键对应的 keyCode == KeyEvent.KEYCODE_ENTER,在onKeyUp方法里判断是这个点击的话,就说明输入结束,要隐藏虚拟按键了。



但是竖屏时的虚拟键盘一般没有这个完成按钮,就无法判断用户何时隐藏虚拟键盘了,当然你可以自定义你的虚拟键盘的Enter按键,也可以实现,只是针对这个问题还是不通用。

于是乎祭出大招了,设置Listener,只要检测到这个黑条出现就调用hideSystemUI方法。

具体代码如下:

   private void setVisibilityListener(){
        View decorView = getWindow().getDecorView();
        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener(){
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                if (visibility == 0){
                    hideSystemUI();
                }
            }
        });
    }
就是设置 OnSystemUiVisibilityChangeListener ,在其 onSystemUiVisibilityChange 中可以获取 SystemUI的显示状态,当 visibility 的值为0时表示SystemUI是显示状态,此时就调用hideSystemUI方法隐藏黑条。P.S.因为正常滑动显示的半透明状态Navigation bar时,这个监听器是不做监听的,所以不必担心正常滑出状态。


坑4--出现虚拟键盘并且旋转屏幕的情况。开始是横屏状态,呼出的虚拟键盘,然后切换到竖屏状态,此时在点击Navigation bar上的返回键,可以隐藏虚拟键盘,但是黑条不会消失。

解决方案:

1.在mainfest中,Activity 属性定义中,写上这个 

android:configChanges="orientation|keyboardHidden|screenSize"
有啥作用呢,就是屏幕旋转的时候,会进
onConfigurationChanged
方法,而不会进onCreate方法,具体可以参考这篇文章 http://www.cnblogs.com/lijunamneg/archive/2013/03/26/2982461.html

然后比较坑的就是 keyboardHidden属性,测试了很长时间,一直以为定义了这个后,虚拟键盘改变状态后就会调用 onConfigurationChanged方法,然而却没有,看了Google官方文档,以及网上所有的解释,都没人说清这个值的作用,个人猜测是和实体键盘有关的,和虚拟键盘无关。

当屏幕旋转后就会进上面的方法。

------------------------------------------------------------------------结局分割线------------------------------------------------------------------------------------

 可能这不是结局,应该还有坑。。。。。。。

综上,为了解决上面的三个坑,需要写三个填坑的方法

1.onResume   --------------------------------------------------- Home 按键坑

2.onWindowFocusChanged  ------------------------------- 锁屏开屏坑

3.OnSystemUiVisibilityChangeListener ----------------- 虚拟键盘坑

4.onConfigurationChanged -------------------------------- 虚拟键盘加旋转屏幕坑

最终的源码如下:

package com.example.lovex.decorviewtest;

import android.content.res.Configuration;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    private final String TAG = "DecorView";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        setVisibilityListener();
    }

    /**
     * 设置System UI显示状态监听
     * 当 visibility 为 0 时,表示Navigation Bar是显示状态,此时进行隐藏
     * 此方法用于解决虚拟键盘呼出后的问题
     */
    private void setVisibilityListener(){
        View decorView = getWindow().getDecorView();
        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener(){
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                if (visibility == 0){
                    hideSystemUI();
                }
            }
        });
    }

    /**
     * 隐藏系统UI,包括顶部Status Bar和底部 Navigation Bar
     */
    private void hideSystemUI(){
        View decorView = getWindow().getDecorView();
        if (decorView != null){
            int uiOptions =  View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;

            decorView.setSystemUiVisibility(uiOptions);
        }
    }

    /**
     * 锁屏开屏返回获取窗口焦点后进行隐藏
     * 此方法用于解决锁屏开屏后的问题
     * @param hasFocus
     */
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus){
            hideSystemUI();
        }
    }

    /**
     * 横竖屏切换时会进入此方法
     * 用来解决弹出虚拟键盘后旋转屏幕后出现的问题
     * @param newConfig
     */
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        hideSystemUI();
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart");
    }

    /**
     * 程序第一次启动以及从后台返回都会调用这个方法
     * 此方法用于解决点击Home键再返回程序的问题
     */
    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume");
        hideSystemUI();
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG, "onRestart");
    }

    /**
     * 这个适用于横屏全屏键盘
     * @param keyCode
     * @param event
     * @return
     */
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP){
            hideSystemUI();
        }
        return super.onKeyUp(keyCode, event);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值