How do I maintain the Immersive Mode in Dialogs?

后端 未结 7 657
醉酒成梦
醉酒成梦 2020-11-28 01:14

How do I maintain the new Immersive Mode when my activities display a custom Dialog?

I am using the code below to maintain the Immersive Mode in Dialogs, but with th

相关标签:
7条回答
  • 2020-11-28 01:31

    If you want to use onCreateDialog(), try this class. It works pretty well for me...

    public class ImmersiveDialogFragment extends DialogFragment {
    
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
    
            AlertDialog alertDialog = new AlertDialog.Builder(getActivity())
                    .setTitle("Example Dialog")
                    .setMessage("Some text.")
                    .create();
    
            // Temporarily set the dialogs window to not focusable to prevent the short
            // popup of the navigation bar.
            alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
    
            return alertDialog;
    
        }
    
        public void showImmersive(Activity activity) {
    
            // Show the dialog.
            show(activity.getFragmentManager(), null);
    
            // It is necessary to call executePendingTransactions() on the FragmentManager
            // before hiding the navigation bar, because otherwise getWindow() would raise a
            // NullPointerException since the window was not yet created.
            getFragmentManager().executePendingTransactions();
    
            // Hide the navigation bar. It is important to do this after show() was called.
            // If we would do this in onCreateDialog(), we would get a requestFeature()
            // error.
            getDialog().getWindow().getDecorView().setSystemUiVisibility(
                getActivity().getWindow().getDecorView().getSystemUiVisibility()
            );
    
            // Make the dialogs window focusable again.
            getDialog().getWindow().clearFlags(
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
            );
    
        }
    
    }
    

    To show the dialog, do the following in your activity...

    new ImmersiveDialogFragment().showImmersive(this);
    
    0 讨论(0)
  • 2020-11-28 01:34

    I know this is old post, but my answer may help others.

    Below is the hacky fix for Immersive effect in Dialogs:

    public static void showImmersiveDialog(final Dialog mDialog, final Activity mActivity) {
            //Set the dialog to not focusable
            mDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
            mDialog.getWindow().getDecorView().setSystemUiVisibility(setSystemUiVisibility());
    
            mDialog.setOnShowListener(new DialogInterface.OnShowListener() {
                @Override
                public void onShow(DialogInterface dialog) {
                    //Clear the not focusable flag from the window
                    mDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
    
                    //Update the WindowManager with the new attributes
                    WindowManager wm = (WindowManager) mActivity.getSystemService(Context.WINDOW_SERVICE);
                    wm.updateViewLayout(mDialog.getWindow().getDecorView(), mDialog.getWindow().getAttributes());
                }
            });
    
            mDialog.getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
                @Override
                public void onSystemUiVisibilityChange(int visibility) {
                    if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                        mDialog.getWindow().getDecorView().setSystemUiVisibility(setSystemUiVisibility());
                    }
    
                }
            });
        }
    
        public static int setSystemUiVisibility() {
            return 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;
        }
    
    0 讨论(0)
  • 2020-11-28 01:36

    Combining the answers here I made an abstract class that works in all cases:

    public abstract class ImmersiveDialogFragment extends DialogFragment {
    
        @Override
        public void setupDialog(Dialog dialog, int style) {
            super.setupDialog(dialog, style);
    
            // Make the dialog non-focusable before showing it
            dialog.getWindow().setFlags(
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
        }
    
        @Override
        public void show(FragmentManager manager, String tag) {
            super.show(manager, tag);
            showImmersive(manager);
        }
    
        @Override
        public int show(FragmentTransaction transaction, String tag) {
            int result = super.show(transaction, tag);
            showImmersive(getFragmentManager());
            return result;
        }
    
        private void showImmersive(FragmentManager manager) {
            // It is necessary to call executePendingTransactions() on the FragmentManager
            // before hiding the navigation bar, because otherwise getWindow() would raise a
            // NullPointerException since the window was not yet created.
            manager.executePendingTransactions();
    
            // Copy flags from the activity, assuming it's fullscreen.
            // It is important to do this after show() was called. If we would do this in onCreateDialog(),
            // we would get a requestFeature() error.
            getDialog().getWindow().getDecorView().setSystemUiVisibility(
                    getActivity().getWindow().getDecorView().getSystemUiVisibility()
            );
    
            // Make the dialogs window focusable again
            getDialog().getWindow().clearFlags(
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
            );
        }
    }
    
    0 讨论(0)
  • 2020-11-28 01:40

    After a lot of research into the issue there is a hacky fix for this, which involved tearing apart the Dialog class to find. The navigation bar is shown when the dialog window is added to the Window Manager even if you set the UI visibility before adding it to the manager. In the Android Immersive example it's commented that:

    // * Uses semi-transparent bars for the nav and status bars
    // * This UI flag will *not* be cleared when the user interacts with the UI.
    // When the user swipes, the bars will temporarily appear for a few seconds and then
    // disappear again.
    

    I believe that's what we're seeing here (that a user-interaction is being triggered when a new, focusable, window view is added to the manager).

    How can we work around this? Make the Dialog non-focusable when we create it (so we don't trigger a user-interaction) and then make it focusable after it's displayed.

    //Here's the magic..
    //Set the dialog to not focusable (makes navigation ignore us adding the window)
    dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
    
    //Show the dialog!
    dialog.show();
    
    //Set the dialog to immersive
    dialog.getWindow().getDecorView().setSystemUiVisibility(
    context.getWindow().getDecorView().getSystemUiVisibility());
    
    //Clear the not focusable flag from the window
    dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
    

    Clearly this is not ideal but it seems to be an Android bug, they should check if the Window has immersive set.

    I've updated my working test code (forgive the hacky messiness) to Github. I've tested on the Nexus 5 emulator, it will probably blow up with anything less than KitKat but its for proof-of-concept only.

    0 讨论(0)
  • 2020-11-28 01:44

    Whean you are creating your own DialogFragment you need only override this method.

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog = super.onCreateDialog(savedInstanceState);
    
        dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
    
        return dialog;
    }
    
    0 讨论(0)
  • 2020-11-28 01:46

    This also works over ride the onDismiss method of your dialog fragment . And within that method call the method of the activity to which it is attached to again set the full screen flags .

    @Override
        public void onDismiss(DialogInterface dialog) {
            super.onDismiss(dialog);
            Logger.e(TAG, "onDismiss");
            Log.e("CallBack", "CallBack");
            if (getActivity() != null &&
                    getActivity() instanceof LiveStreamingActivity) {
                ((YourActivity) getActivity()).hideSystemUI();
            }
        }
    

    And in your activity add this method :

    public 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.
            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 // hide nav bar
                            | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
                            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
        }
    
    0 讨论(0)
提交回复
热议问题