沉浸式模式导航在音量调整或最小化/还原后变得粘滞。

30
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        this.getWindow().getDecorView().setSystemUiVisibility(getSystemUiFlags());
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    private static int getSystemUiFlags() {
            return View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
    }

}

第一次启动后

第一次启动后

按下音量按钮或最近按两次应用程序后

输入图像描述

我发现QuickPic应用程序没有这个错误。 我想知道他们是如何遗漏它的。

3个回答

61

以下代码对我有效:

public void updateUI() {
    final View decorView = getWindow().getDecorView();
    decorView.setOnSystemUiVisibilityChangeListener (new View.OnSystemUiVisibilityChangeListener() {
        @Override
        public void onSystemUiVisibilityChange(int visibility) {
            if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                decorView.setSystemUiVisibility(
                        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);
                }
            }
        });
}

并在onCreateonResume方法上调用了监听器:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    updateUI();
}

@Override
public void onResume() {
    super.onResume();
    updateUI();
}

1
@Peter Brooks 我已经尝试过这个方法,虽然它修复了沉浸模式,但导航栏在可见的第二秒确实是黑色的。 - Rudey
8
对于键盘出现的情况,它对我不起作用。 - Menna-Allah Sami
1
它仍然会显示一秒钟,但至少我的内容没有移动,这对我帮助很大 :) - OlivierM
1
不得不在onResume中调用它。谢谢 - Diljeet
1
相关文档:https://developer.android.com/training/system-ui/visibility.html - ajh158
显示剩余5条评论

29

我的解决方案是在三个位置设置UI-可见性标志:

  1. 当获得焦点时
  2. 在onResume中
  3. 在OnSystemUiVisibilityChangeListener监听器中

第三个解决了我的问题。其他的可能不是必需的,但我保留了它们。 这就是它的样子:

  private void setupMainWindowDisplayMode() {
    View decorView = setSystemUiVisilityMode();
    decorView.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
      @Override
      public void onSystemUiVisibilityChange(int visibility) {
        setSystemUiVisilityMode(); // Needed to avoid exiting immersive_sticky when keyboard is displayed
      }
    });
  }

  private View setSystemUiVisilityMode() {
    View decorView = getWindow().getDecorView();
    int options;
    options =
        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 // hide nav bar
      | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
      | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;

    decorView.setSystemUiVisibility(options);
    return decorView;
  }

setupMainWindowDisplayMode()在onCreate()中被调用。


1
仅仅第三个选项是不够的。经过大量测试,我发现 OnSystemUiVisibilityChangeListener 并不总是会触发。我通过添加第一个选项来解决这个问题,但为了确保,我还实现了第二个选项。好答案 :) - Rudey
你的意思是在onWindowFocusChanged中调用选项一吗? - Menna-Allah Sami
20
呃,有时候安卓开发真的很糟糕。 - Dean Wild
1
非常好,解决了我大部分的问题。 - Gilian
当对话框或下拉菜单显示时,它们有自己的窗口,因此设置Activity的setSystemUiVisilityMode没有效果,导航UI仍然显示。 - activity
Has to be the 3 options :D - CarLoOSX

19

我曾经遇到同样的问题,但是我用一个简单的解决方案解决了它。虽然我找不到这个解决方案的理论原因,但它确实对我有用。

似乎当按下音量按钮时,与“沉浸模式”相关的“标志”被清除。我认为这就是为什么沉浸模式被禁用并且沉浸模式没有自动恢复的原因。

因此,我尝试在按下音量按钮后使用“runnable”对象设置“标志”。

所以,它的工作原理如下:

沉浸模式 -> 按下音量按钮(标志已清除) -> 500毫秒后,可运行对象再次设置标志 -> 沉浸模式恢复

1. 首先,定义可运行对象来设置标志

private Runnable decor_view_settings = new Runnable()
{
    public void run() 
    {
        getWindow().getDecorView().setSystemUiVisibility(
                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);
    }
};

2. 当音量按钮被按下时,将可运行对象延迟一段时间后发布到处理程序中

private Handler mHandler = new Handler();

...

@Override 
public boolean onKeyDown(int keyCode, KeyEvent event) 
{
    if(keyCode == KeyEvent.KEYCODE_BACK)
    {
        finish();
    }
    else if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP)
    {
        mHandler.postDelayed(decor_view_settings, 500);
    }

    return super.onKeyDown(keyCode, event);
}

我刚刚没有任何原因地延迟了500毫秒,这并不重要。

3. 使用可运行对象实现沉浸式模式的基本代码

@Override
public void onWindowFocusChanged(boolean hasFocus) 
{
    super.onWindowFocusChanged(hasFocus);

    if(hasFocus) 
    {
        mHandler.post(decor_view_settings);
    }
}

我的应用程序上它完美地运作了。

所以,当我按音量按钮时,全屏模式会被禁用,音量控制器弹出。

几秒钟后,音量控制器消失,状态栏和导航栏也会消失。

希望这对你有用。


谢谢,完美运作,这应该被接受为最佳答案! - Toni Alvarez
1
即使在这个“延迟”修复期间,当我在应用程序之间切换时仍然存在问题。调用setSystemUiVisibility两次有所帮助:首先没有SYSTEM_UI_FLAG_IMMERSIVE_STICKY,然后再次使用SYSTEM_UI_FLAG_IMMERSIVE_STICKY。更多细节请参见:http://vitiy.info/small-guide-how-to-support-immersive-mode-under-android-4-4/ - Victor Laskin
哇,这真的起作用了。键盘的消失并不总是能够为我们摆脱键盘。等待更改通知略微更有效,但在旧设备上仍存在某种竞争条件,但只需钩入可见性更改即可在需要隐藏导航栏时将其去除。谢谢! - Hunter-Orionnoir
谢谢。当 ImageView 被点击时,我正在全屏显示它的 Bitmap 在一个新的 fragment 中。然而,全屏后底部出现了状态栏大小的空白空间。在 onCreateView() 中使用 View#post(Runnable) 对我有用。 - Lym Zoy
这个解决方案真的很有效,应该被接受为答案!感谢您出色的工作。 - Bhavik Mehta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接