安卓如何隐藏导航栏/保持沉浸模式并显示软键盘

34

我正在处理一个客户的应用程序,该应用程序使用以下代码在每个活动中使用沉浸模式来隐藏导航栏和状态栏:

int currentApiVersion = android.os.Build.VERSION.SDK_INT;

final int flags = 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;

// This work only for android 4.4+
if (currentApiVersion >= 19) {

        getWindow().getDecorView().setSystemUiVisibility(flags);
        // Code below is for case when you press Volume up or Volume down.
        // Without this after pressing valume buttons navigation bar will
        // show up and don't hide
        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(flags);
                        }
                }
         });
}

唯一的问题是,他们希望应用程序保持沉浸模式,即使软键盘显示在EditText中输入时也不显示导航栏。有没有人想到一种方法,即使使用键盘,也始终隐藏导航按钮(返回/隐藏键盘,主页等)?


1
我现在正面临着同样的问题。我尝试了几乎所有我能想到的方法,但似乎导航栏与软键盘相连。你有找到解决方法吗? - a54studio
2
不,我没有这样做。导航是软键盘的一部分。您可以创建自己的自定义键盘,即使在沉浸模式下仍然可以显示,但在沉浸模式下失去了许多键盘所需的功能。因此,目前似乎没有好的方法可以在保持沉浸模式的同时输入文字。希望未来会出现这样的方法。如果有人知道,请告诉我们。 - Chris Klingler
1
我能想到的唯一方法就是创建自己的键盘功能。我认为在使用Android键盘时无法隐藏导航栏。 - Rudey
这个回答解决了你的问题吗?软键盘弹出后禁用粘性沉浸模式 - TylerH
5个回答

12

我想到了一个方法,它会在每次内部导航时检查导航栏的状态,尝试隐藏它并再次检查(多次)。

以下是一段代码片段,确保软键盘关闭后2秒钟内导航栏被隐藏。

  private final Runnable checkSystemUiRunnable = new Runnable() {
    @Override
    public void run() {
      checkHideSystemUI();
    }
  };

  private void checkHideSystemUI() {
    // Check if system UI is shown and hide it by post a delayed handler
    if (isSystemUiShown) {
      hideSystemUI();
      handler.postDelayed(checkSystemUiRunnable, SYSTEM_UI_HIDE_DELAY);
    }
  }

  private void hideSystemUI() {
    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 // hide nav bar
                    | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
                    | View.SYSTEM_UI_FLAG_IMMERSIVE);
  }

  // In onCreate()
    decorView.setOnSystemUiVisibilityChangeListener(
            new View.OnSystemUiVisibilityChangeListener() {
              @Override
              public void onSystemUiVisibilityChange(int visibility) {
                if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                  handler.postDelayed(checkSystemUiRunnable, SYSTEM_UI_HIDE_DELAY);
                  isSystemUiShown = true;
                } else {
                  isSystemUiShown = false;
                }
              }
            });

我觉得这种编写代码的方式很奇怪,而且它缺少处理应用切换或活动切换的部分。请在此处查看解决方案,特别是最后一个评论:https://dev59.com/aWEi5IYBdhLWcg3wjs5j#21253443 - pbristow
谢谢伙计,你节省了我的时间。 - Rameshbabu

6

以下是我对此问题的解决方案;首先,我检查软键盘是否已经显示:

getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {

                Rect r = new Rect();
                getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
                int screenHeight = getWindow().getDecorView().getRootView().getHeight();

                int keypadHeight = screenHeight - r.bottom;

                //Log.d(TAG, "keypadHeight = " + keypadHeight);

                if (keypadHeight > screenHeight * 0.15) { 
                     //Keyboard is opened
                     hideNavBar();
                }
                else {
                    // keyboard is closed
                }
            }
        });

我有一个hideNavBar()方法,应该在软键盘弹出时触发。

private void hideNavBar() {
    if (Build.VERSION.SDK_INT >= 19) {
        View v = getWindow().getDecorView();
        v.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);
    }
}

这可以解决在有Edittext需要输入时获取导航栏的问题。

在Android 5.1上,我不得不添加View.SYSTEM_UI_FLAG_LOW_PROFILE来完全隐藏按钮。 - Ian Butler

1

更新时间:

我有一个绘画应用程序(Paint Shapes),这是我用来一直处于沉浸模式的配置。我使用onWindowFocusChanged方法。

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        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);
    }
}

1
@ahmednabil88,感谢您的反馈,我刚刚更新了我的个人应用程序中实际使用的配置。 - Benny

0

最有效的方法是仅在需要时设置SystemUIVisibility:

  1. 在您的onCreate()中
  2. 当全屏模式丢失时,使用OnSystemUIChangeListener

我使用并推荐的解决方案:

public class BaseActivity extends Activity {

    @SuppressLint("InlinedApi")
    private static final int UI_OPTIONS = View.SYSTEM_UI_FLAG_LOW_PROFILE
            | View.SYSTEM_UI_FLAG_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;        

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Step 1
        hideSystemUI();

        // Step 2
        getWindow().getDecorView()
                   .setOnSystemUiVisibilityChangeListener(new View
                   .OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                    hideSystemUI();
                }
            }
        });
    }
    
    private void hideSystemUI() {
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) actionBar.hide();
        getWindow().getDecorView().setSystemUiVisibility(UI_OPTIONS);
    }

}

0
我认为这是不可能的。在这里,Flutter:如何在聚焦文本字段时显示屏幕键盘而不使用 Android 底部导航栏?已经明确说明,我的经验也证实了它。
以下代码放置在一个活动中。
private var appVisibility:Int = (  View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                                or View.SYSTEM_UI_FLAG_LOW_PROFILE
                                or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                                or View.SYSTEM_UI_FLAG_FULLSCREEN
                                or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    window.decorView.systemUiVisibility = appVisibility

}
override fun onResume() {
    super.onResume()
    updateUI()
}
fun updateUI() {
    val decorView = window.decorView
    decorView.setOnSystemUiVisibilityChangeListener { visibility ->
        if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
            decorView.systemUiVisibility = appVisibility
        }
    }
}

正确地隐藏导航栏(当您从屏幕底部滑动时,导航栏会出现几秒钟,然后消失),但当键盘打开时不起作用。我还尝试了通过编程方式打开键盘,然后在几秒钟后隐藏导航栏,但没有成功。

private fun toggleIME(){
    val imm             = applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager?
    val view: EditText? = text

    if(view != null && imm != null) {
        isKOpen = !isKOpen
        if (isKOpen) {
            view.requestFocus()
            imm.showSoftInput(view, InputMethodManager.SHOW_FORCED)

            handler.postDelayed(Runnable { // execute after XXXms
                updateUI()
                window.decorView.systemUiVisibility = appVisibility
            }, 5000)

        }
        else {
            imm.hideSoftInputFromWindow(view.windowToken, 0)
        }
    }
}

我希望我有所遗漏。我需要这个用于我正在开发的自定义键盘(其中我需要实现返回按钮)。


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