当使用具有对话框的沉浸模式时,导航。栏重新出现并调整我的布局大小

时间:2014-03-22 12:34:20

标签: android android-activity android-ui android-dialog android-4.4-kitkat

我在我的应用中使用沉浸式模式,当它在Android 4.4及更高版本上运行时。 (http://developer.android.com/training/system-ui/immersive.html

我的活动确实以全屏显示,我使用setOnSystemUiVisibilityChangeListener按下音量键。我也有类似的代码将对话框放入沉浸式模式。

但是,当显示对话框时,导航。酒吧跳到屏幕上,然后立即撤退。当对话框被解除时,情况会更糟 - 导航。酒吧跳跃并调整背后的活动。

以下是我的支持沉浸式模式的课程。它只是在每个Activity的onResume上调用,并且在构建每个对话框时也会调用一个单独的函数。

我是否错过任何旗帜或回调,或者这是一个已知的Android问题?

public class ImmersiveModeHelper {

    public ImmersiveModeHelper(Activity activity)
    {
        mActivity = activity;
    }

    @SuppressLint("NewApi")
    public void supportFullScreenImmersiveMode()
    {
        MyLog.d("ImmersiveModeHelper: supportFullScreenImmersiveMode: ");

        // Support full-screen immersive mode on Android 4.4 and up
        if (Build.VERSION.SDK_INT >= 19)
        {
            // Get the needed flags by reflection and use them
            try
            {
                final int immersiveFlag = View.class.getField("SYSTEM_UI_FLAG_IMMERSIVE_STICKY")
                        .getInt(null);
                final int hideNavigationFlag = View.class
                        .getField("SYSTEM_UI_FLAG_HIDE_NAVIGATION").getInt(null);
                final int fullScreenFlag = View.class.getField("SYSTEM_UI_FLAG_FULLSCREEN").getInt(
                        null);


                // Set the flags to the window decor view
                mActivity.getWindow().getDecorView()
                        .setSystemUiVisibility(immersiveFlag | hideNavigationFlag | fullScreenFlag);

                // Set a callback to be called when visibility changes
                // (workaround
                // for volume keys)
                mActivity
                        .getWindow()
                        .getDecorView()
                        .setOnSystemUiVisibilityChangeListener(
                                new View.OnSystemUiVisibilityChangeListener()
                                {
                                    @Override
                                    public void onSystemUiVisibilityChange(int visibility)
                                    {
                                        MyLog.d("ImmersiveModeHelper.supportFullScreenImmersiveMode().new OnSystemUiVisibilityChangeListener() {...}: onSystemUiVisibilityChange: " +
                                                "");

                                        if ((visibility & (immersiveFlag | hideNavigationFlag)) == 0)
                                        {
                                            Handler uiHandler = UiThreadUtils.getUiHandler();
                                            uiHandler.removeCallbacks(mHideSystemUiCallback);
                                            uiHandler.postDelayed(mHideSystemUiCallback,
                                                    HIDE_SYSTEM_UI_DELAY_MILLI);
                                        }
                                    }
                                });

            } catch (Exception e)
            {
                e.printStackTrace();
                MyLog.e("ImmersiveModeHelper: supportFullScreenImmersiveMode: couldn't support immersive mode by reflection");
            }
        } else
        {
            MyLog.i("ImmersiveModeHelper: supportFullScreenImmersiveMode: not supported on this platform version");
        }
    }

    public static void supportFullScreenImmersiveModeForDialog(final Dialog dlg)
    {
        MyLog.d("ImmersiveModeHelper: supportFullScreenImmersiveModeForDialog: ");

        // Support full-screen immersive mode on Android 4.4 and up
        if (Build.VERSION.SDK_INT >= 19)
        {
            final Window dlgWindow = dlg.getWindow();

            // Get the needed flags by reflection and use them
            try
            {
                final int immersiveFlag = View.class.getField("SYSTEM_UI_FLAG_IMMERSIVE_STICKY")
                        .getInt(null);
                final int hideNavigationFlag = View.class
                        .getField("SYSTEM_UI_FLAG_HIDE_NAVIGATION").getInt(null);
                final int fullScreenFlag = View.class.getField("SYSTEM_UI_FLAG_FULLSCREEN").getInt(
                        null);


                // Set the flags to the window decor view
                int flags = dlgWindow.getDecorView().getSystemUiVisibility();
                flags |= (immersiveFlag | hideNavigationFlag | fullScreenFlag);
                dlgWindow.getDecorView().setSystemUiVisibility(flags);

                // Set a callback to be called when visibility changes
                // (workaround for volume keys)
                dlgWindow.getDecorView().setOnSystemUiVisibilityChangeListener(
                        new View.OnSystemUiVisibilityChangeListener()
                        {
                            @Override
                            public void onSystemUiVisibilityChange(int visibility)
                            {
                                MyLog.d("ImmersiveModeHelper.supportFullScreenImmersiveModeForDialog(...).new OnSystemUiVisibilityChangeListener() {...}: onSystemUiVisibilityChange: ");
                                if ((visibility & (immersiveFlag | hideNavigationFlag)) == 0)
                                {
                                    Runnable hideSystemUiCallback = new Runnable()
                                    {
                                        @Override
                                        public void run()
                                        {
                                            supportFullScreenImmersiveModeForDialog(dlg);
                                        }
                                    };

                                    Handler uiHandler = UiThreadUtils.getUiHandler();
                                    uiHandler.removeCallbacks(hideSystemUiCallback);
                                    uiHandler.postDelayed(hideSystemUiCallback,
                                            HIDE_SYSTEM_UI_DELAY_MILLI);
                                }
                            }
                        });

            } catch (Exception e)
            {
                e.printStackTrace();
                MyLog.e("ImmersiveModeHelper: supportFullScreenImmersiveMode: couldn't support immersive mode by reflection");
            }
        } else
        {
            MyLog.i("ImmersiveModeHelper: supportFullScreenImmersiveMode: not supported on this platform version");
        }
    }

    private Activity mActivity;

    private Runnable mHideSystemUiCallback = new Runnable()
    {
        @Override
        public void run()
        {
            supportFullScreenImmersiveMode();
        }
    };

    private static final int HIDE_SYSTEM_UI_DELAY_MILLI = 0;

}

3 个答案:

答案 0 :(得分:4)

来自Google API: 包含其他系统UI标志(例如SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION和SYSTEM_UI_FLAG_LAYOUT_STABLE)以保持内容在系统栏隐藏和显示时不会调整大小是一种很好的做法。

您还应确保同时隐藏操作栏和其他UI控件。此代码段演示了如何隐藏和显示状态和导航栏,而无需调整内容大小:

// This snippet hides the system bars.
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);
}

// This snippet shows the system bars. It does this by removing all the flags
// except for the ones that make the content appear under the system bars.
private void showSystemUI() {
    mDecorView.setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}

希望这有帮助。

答案 1 :(得分:0)

在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)

}

现在看魔术:)

答案 2 :(得分:0)

对我有用的是将以下内容添加到父布局xml:

android:fitsSystemWindows="true"