Immersive Mode in Android 4.4 KitKat

October 31, 2013 Google introduced a new version of Android 4.4 KitKat, which has a lot of interesting features for developers. One of these features is Immersive Mode . Immersion mode is a mode in which your program is displayed to the user in full screen, while any system panels, including the navigation panel (the one with the Back button), are not visible. Prior to Android 4.4, there was also the ability to hide system panels ( navigation bar and status bar) But in the existing version there was one drawback - the user could not completely plunge into the content, since any click on the content again caused the display of system panels. The new dive mode adds another way to interact with the display of system panels. In this mode, to display the system panels, it is enough for the user to swipe from the top or bottom edge of the screen towards the center of the screen, while displaying panels by clicking on the content is optional, thereby creating applications and games in which the user can fully interact with application or game by any gestures. In order for the user to understand how to call up the system panels from full screen mode, the first time the application is launched, he will automatically be shown a system message on how to display these panels on the screen again.

imageimage

You might also think that there is another problem using this mode. For example, a user has started a drawing program and wants to draw a line from the edge of the screen, and how is it, will he really see a system panel in this case. Yes, but the application will also receive messages from taps on the screen and will draw a line. By the way, now you can simply make the system panels translucent with two new themes - Theme.Holo.NoActionBar.TranslucentDecor and Theme.Holo.Light.NoActionBar.TranslucentDecor. But it is worth remembering that in this case, your content will occupy the entire area on the screen and will be visible even behind translucent system panels. If you need some part of the interface not to go beyond system panels (for example, some additional panels), you need to set the fitsSystemWindows attribute to true for the parent layout of this content . Not a very pleasant thing with these themes is that they use inferior translucency for panels, but gradient (from black to translucent), which does not always look beautiful. If you create your own custom theme, you can either inherit from these new themes, or manually add two new windowTranslucentNavigation properties (is the system navigation panel transparent) andwindowTranslucentStatus (whether the system status bar is transparent with a watch).

But how do you get into full-screen mode again when the panels are already displayed? The user has several options - click on any content outside the system panels, wait a while for the panels to disappear automatically, or swipe from the center of the screen to the edge. The programmer can provide all these options in his application. To do this, the Android team has made it very easy to implement these ways of interacting with Immersive Mode. There are two types of dive modes - regular and sticky.("sticky"). In normal mode, the programmer must decide when to hide the panels, and in sticky-mode, the system panels will be hidden automatically. To set both types of dive modes, you must use the setSystemUiVisibility () method , only pass different flags to the parameters. This method must be called on the so-called Decor View, which is the appearance of the Activity window with all its design and content. Link to this View is very simple.

mDecorView = getWindow().getDecorView();

Let's look at both types of dive modes in more detail.

Normal Immersive Mode


To set normal mode, use the SYSTEM_UI_FLAG_IMMERSIVE flag as a parameter to the setSystemUiVisibility () method .

It is best to make two simple methods for working with the normal immersive mode, which will show and hide the system panels, respectively.

    private void hideSystemUI() {
        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
                | View.SYSTEM_UI_FLAG_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LOW_PROFILE
                | View.SYSTEM_UI_FLAG_IMMERSIVE);
    }
    private void showSystemUI() {
        mDecorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
    }

For those cases when you need to show and hide system panels by clicking on the content ( contentView ), you must use the following code. This can be useful, for example, when watching a video, as in YouTube, where you do not need to interact with the content while watching it.

        contentView.setClickable(true);
        final GestureDetector clickDetector = new GestureDetector(this,
                new GestureDetector.SimpleOnGestureListener() {
                    @Override
                    public boolean onSingleTapUp(MotionEvent e) {
                        boolean visible = (mDecorView.getSystemUiVisibility()
                                & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
                        if (visible) {
                            hideSystemUI();
                        } else {
                            showSystemUI();
                        }
                        return true;
                    }
                });
        contentView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                return clickDetector.onTouchEvent(motionEvent);
            }
        });

If at the same time in your application you have some of your own panels ( controlsView ), which also need to be hidden together with the system ones, you can also just do this by writing the following code. Here, hiding and appearing is done using the alpha channel animation and the Y position of your panel.

        mDecorView.setOnSystemUiVisibilityChangeListener(
                new View.OnSystemUiVisibilityChangeListener() {
                    @Override
                    public void onSystemUiVisibilityChange(int flags) {
                        boolean visible = (flags & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
                        controlsView.animate()
                                .alpha(visible ? 1 : 0)
                                .translationY(visible ? 0 : controlsView.getHeight());
                    }
                });

If when you start the application you want to show the user that the application has panels, and then hide them after a while, this is also quite simple.

    private static final int INITIAL_HIDE_DELAY = 300;
    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        delayedHide(INITIAL_HIDE_DELAY);
    }
    private final Handler mHideHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            hideSystemUI();
        }
    };
    private void delayedHide(int delayMillis) {
        mHideHandler.removeMessages(0);
        mHideHandler.sendEmptyMessageDelayed(0, delayMillis);
    }

Also, sometimes it may be necessary to show the panel when the window receives focus, for example, after returning from the called dialog. This option can be processed with the following code.

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus) {
            delayedHide(INITIAL_HIDE_DELAY);
        } else {
            mHideHandler.removeMessages(0);
        }
    }

In this case, the panel will appear and then disappear after the time you set.

Immersive mode sticky


To set sticky mode, the SYSTEM_UI_FLAG_IMMERSIVE_STICKY flag is used as a parameter to the setSystemUiVisibility () method .

This mode is extremely simple. If you need a situation in which system panels will be hidden when the window receives focus or passes some time after the panels appear, then this mode is for you. To enable this mode, you need to set the SYSTEM_UI_FLAG_IMMERSIVE_STICKY flag for the window when it is in focus . In this mode, if the window loses focus, it is automatically reset to the state in which the window was before setting the SYSTEM_UI_FLAG_IMMERSIVE_STICKY flag, that is, with all panels. As soon as the window receives focus, the panels disappear again after a while and you do not need to program this situation manually. To show the system panels, you must also, as in normal mode, make a swipe from the edges of the screen. Enabling stick mode is done with a simple piece of code.

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


PS The article used video materials from Roman Nurik . The code of full examples from Roman on using this mode can be downloaded here .

PPS On November 20, a new article appeared in the Training Kit on this regimen. I will try to supplement the article in the near future, taking into account her.

Also popular now: