显示DialogFragment时保持沉浸式模式

时间:2015-09-24 10:02:49

标签: android keyboard android-dialogfragment android-immersive

我有一个使用Fragments制作的Android应用程序

我使用以下代码隐藏了屏幕顶部和底部的条形图。

 @Override
protected void onResume() {
    super.onResume();
    isInBackground = false;

    if(null == getFragmentManager().findFragmentById(R.id.content_container))
    {
        getFragmentManager().beginTransaction().add(R.id.content_container,new PresenterFragment(), PresenterFragment.FRAG_TAG).commit();
    }

    if(Build.VERSION.SDK_INT >=19)
    {
        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 // hide nav bar
                | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
        decorView.setSystemUiVisibility(uiOptions);
        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                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 // hide nav bar
                        | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
                decorView.setSystemUiVisibility(uiOptions);
            }
        });
    }
}

当它显示条形显示的软键盘时,我可以使用它,因为它们在键盘被关闭时隐藏。但是如果在显示软键盘时显示对话框片段,那么键盘和对话框片段都是被驳回他们的酒吧仍然在申请的顶部。

我的3个问题是

是否可以停止软键盘以更改UI模式?

是否可以停止显示DialogsFraments以更改UI模式?

编辑:我曾经在下面的代码中查看键盘是否显示

public static boolean isKeyBoardShown(){
    InputMethodManager imm = (InputMethodManager)currentActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
    if (imm.isAcceptingText()) {
        return true;
    } else {
        return false;
    }
}

- >我知道在活动中有一个解决对话框的工作但我无法看到一个或重新编写代码以在DialogFragment中工作

如果两者都不可能,为什么当显示键盘和DialogFrament时,应用程序会陷入错误的UI模式?

5 个答案:

答案 0 :(得分:31)

<强> 1。解决方案说明。

我从android api docs中采用了以下引用。

Using Immersive Full-Screen Mode

  

启用沉浸式全屏模式后,您的活动将继续   接收所有触摸事件。用户可以用一个显示系统栏   向内滑动系统条通常出现的区域。   这将清除SYSTEM_UI_FLAG_HIDE_NAVIGATION标志(和   SYSTEM_UI_FLAG_FULLSCREEN标志(如果已应用),以便系统栏成为   可见。这也会触发你的   View.OnSystemUiVisibilityChangeListener,如果设置。

首先,使用粘性浸泡时,您不需要OnSystemUiVisibilityChangeListener

  

但是,如果您希望系统栏再次自动隐藏   过了一会儿,你可以改用   SYSTEM_UI_FLAG_IMMERSIVE_STICKY标志。请注意“粘性”版本   标志不会触发任何侦听器,因为系统暂时禁止   此模式下显示处于暂态状态。

recommendations for using sticky/non sticky immersion

  

如果您正在构建一个真正身临其境的应用,那么您希望用户在哪里   在屏幕边缘附近进行交互,你不期望它们   需要经常访问系统UI,使用IMMERSIVE_STICKY标志   与SYSTEM_UI_FLAG_FULLSCREEN和。一起使用   SYSTEM_UI_FLAG_HIDE_NAVIGATION。例如,这种方法可能是   适合游戏或绘图应用。

但是,你提到需要键盘的用户,所以我建议:
 Use Non-Sticky Immersion

  

如果您正在构建图书阅读器,新闻阅读器或杂志,请使用   IMMERSIVE标志与SYSTEM_UI_FLAG_FULLSCREEN和   SYSTEM_UI_FLAG_HIDE_NAVIGATION。因为用户可能想要访问   操作栏和其他UI控件有点频繁,但不是   翻阅内容时,任何UI元素都会受到困扰,   对于这个用例,IMMERSIVE是一个很好的选择。

<强> 2。溶液

我的解决方案是在片段的onActivityCreated中设置你的视图ui。

我的例子取自ImmersiveModeFragment.java样本。

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    final View decorView = getActivity().getWindow().getDecorView();
    decorView.setOnSystemUiVisibilityChangeListener(
            new View.OnSystemUiVisibilityChangeListener() {
                @Override
                public void onSystemUiVisibilityChange(int i) {
                    hideSystemUI();
                }
            });
}

创建一个单独的方法来管理您从OnSystemUiVisibilityChangeListener()

调用的ui

从这里采取non sticky immersion

private void hideSystemUI() {
    // Set the IMMERSIVE flag.
    // Set the content to appear under the system bars so that the content
    // doesn't resize when the system bars hide and show.
    mDecorView.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);
}

然后,您可以再次调用此方法onResume

onResume(){
    hideSystemUI();
}

第3。替代解决方案。

如果你真正想要粘性沉浸,你需要尝试不同的方法。

For sticky immersion

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus) {
        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);}
}

我希望这能解决你的问题。

答案 1 :(得分:2)

  

是否可以停止软键盘以更改UI模式?

也许

  

是否可以停止显示DialogsFraments以更改UI模式?

是的,只要你试着了解你在做什么

  

如果两者都不可能,为什么当显示键盘和DialogFrament时,应用程序会陷入错误的UI模式?

因为问题2的答案

现在这是您的整体解决方案

当前/聚焦视图是操作系统获取UI可见性设置的人,当视图被遮挡或者在z顺序上不在顶部时,setSystemUiVisibility()被设置为默认值。 S o反而尝试黑客攻击

View decorView = getWindow().getCurrentFocus() != null ? 
                getWindow().getCurrentFocus() :getWindow().getDecorView();

每当您的DialogFragment被解雇时,请检查上述行并重新拨打您的辅助功能ui代码;因为....猜到这一点是清醒的

答案 2 :(得分:2)

我知道这很旧了,但是由于我有DialogueFragments和我的navigationView中的下拉菜单,我一直在为此苦苦挣扎一会儿,从而不断显示系统UI。这是我所做的最终起作用的事情(前两件我发现了很多地方):

在我的AndroidManifest.xml上的应用程序中

android:theme="@style/AppTheme.NoActionBar"

在我的活动中

View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
decorView.setSystemUiVisibility(uiOptions);

最终成为我关键的是我的styles.xml

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowFullscreen">true</item>
    </style>
</resources>

答案 3 :(得分:1)

此修补程序以及与软键盘相关的其他修复程序包含在此库的DialogFragment类中。只需扩展它而不是标准库:

https://github.com/marksalpeter/contract-fragment

该库的主要用途是将片段功能添加到利用父/子片段关系的Fragments和DialogFragments,但您可以使用错误修复或复制/粘贴文件

答案 4 :(得分:1)

在Dialog或BottomSheetDialogFragment中,您必须实现对我有用的解决方案。

第1步:

在对话框或BottomSheetDialog中,使用onActivityCreated方法编写此代码,

override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
var viewParent = view
while (viewParent is View) {
    viewParent.fitsSystemWindows = false
    viewParent.setOnApplyWindowInsetsListener { _, insets -> insets }
    viewParent = viewParent.parent as View?
 }
}

步骤2:此外,请覆盖以下方法:

override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style)
dialog?.window?.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)

}

现在看魔术:)