Prudhvi
Prudhvi

Reputation: 2343

How to hide status and navigation bars after first touch event?

I have been using the flags SYSTEM_UI_FLAG_FULLSCREEN and SYSTEM_UI_FLAG_HIDE_NAVIGATION to hide and show both the status and navigation bars. They are working correctly. I am hiding them as the activity starts and I want to show them again on touch event. Android automatically shows them on first touch event (this first touch event is not passed to my app). I'm thinking to use sendMessageDelayed() to hide both the bars after a certain time. How could I use this first touch event?

Upvotes: 2

Views: 6004

Answers (2)

risto
risto

Reputation: 100

-If you want to hide the navigation bar, you will encounter the problem with the first touch event and your app will not be able to do anything with it.

-If you want you can use postDelayed() to hide the bars after certain time, here is what I have done:

Runnable navHider = new Runnable() {
    @Override
    public void run() {
        Log.e("HIDING", "hide");
        hideSystemUi();
    }

/** Hides StatusBar and NavigationBar */
private void hideSystemUi() {
    if (isLandscape()) {
        // Set flags for hiding status bar and navigation bar
        View decorView = ((Activity) context).getWindow().getDecorView();
         // Hide the status bar.
         int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
         | View.SYSTEM_UI_FLAG_FULLSCREEN
         | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
         | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
         | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
        int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
        decorView.setSystemUiVisibility(uiOptions);

    }
}

private void setVisibilityChangeListener() {
    View decorView = ((Activity) context).getWindow().getDecorView();
    decorView
            .setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
                @Override
                public void onSystemUiVisibilityChange(int visibility) {
                    // Note that system bars will only be "visible" if none
                    // of the
                    // LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are
                    // set.
                    if (isLandscape()) {
                        if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                            getHandler().postDelayed(navHider,
                                    UI_VISIBILITY_TIME);
                        }
                    }
                }
            });
}

What we are doing here is:

-First, the navHider is a Runnable object which is hiding the systemUI.

-Second, the hideSystemUi method is sets the UI options flags for hiding the status and navigation bar (Note that we are also using LAYOUT_STABLE Flag so the content would appear behind the status bar and navigation bars and we wont need to resize the content.)

-Third, we are using the systemUIVisibilityChangeListener, so that after the user interacts with the screen and the status and navigation bars show, we use the postDelayed(), where the UIVisibility time is the time, you want to wait before we hide the status and navigation bars

You can also show/hide the status bar on every touch event (or clicking a button and etc) We can do this only for the status bar but not for the navigation bar:

/** Hides StatusBar and NavigationBar */
private void hideSystemUi() {
    if (isLandscape()) {
        // Set flags for hiding status bar and navigation bar
        View decorView = ((Activity) context).getWindow().getDecorView();
        // // Hide the status bar.
        int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
        decorView.setSystemUiVisibility(uiOptions);

        Window window = ((Activity) context).getWindow();
        window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
        ((Activity) context).getActionBar().hide();
        isShowing = false;
    }
}

private void showSystemUi() {
    View decorView = ((Activity) context).getWindow().getDecorView();
    Window window = ((Activity) context).getWindow();
    decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
    window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
    ((Activity) context).getActionBar().show();
    isShowing = true;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_UP) {
        if (isShowing) {
            Log.e("onInterceptTouchEvent", "Hiding System UI");
            hideSystemUi();
        } else {
            Log.e("onInterceptTouchEvent", "Showing System UI");
            showSystemUi();
        }
    }
    return super.onInterceptTouchEvent(event);

}

Note that in those 2 methods: hideSystemUI() and showSystemUI(), to avoid the annoying "first touch event" we are using the old pre 4.0 flags, for hiding the status bar.

I am using this code in my ViewPager (Which I am using to show images), so I can override the onInterceptTouchEvent() method. Here I check if the system is showing or not, with a simple boolean. Also you need to use MotionEvent.ACTION_UP, this will allow you to scroll the ViewPager, without actually showing/hiding the status bar accidentally, so you can scroll in fullscreen mode.

What you can do is make a custom layout (Lets say RelativeLayout), which extends ViewGroup and you can overwrite onInterceptTouchEvent and make this implementation. The touch event will work only on that CustomRelativeLayout, so if you want for it to work on the whole activity, just make CustomRelativeLayout your base layout with the match_parent attributes for height/width.

Here is info for showing and hiding status and navigation bars. https://developer.android.com/training/system-ui/status.html https://developer.android.com/training/system-ui/navigation.html

And this is a link, for managing touch events. https://developer.android.com/training/gestures/viewgroup.html

Upvotes: 0

Prudhvi
Prudhvi

Reputation: 2343

I got it by using View.OnSystemUiVisibilityChangeListener. I have just used a Handler.sendMessageDelayed inside the if condition when both status and navigation bars are visible. See the below implementation for clarity.

Source : Responding to UI Visibility Changes

View decorView = getActivity().getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {@Override
    public void onSystemUiVisibilityChange(int visibility) {
        if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
            // TODO: The system bars are visible. Make any desired
            Message msg = mHandler.obtainMessage(HIDE_STATUSBAR); //Implement your hide functionality accordingly                
            mHandler.sendMessageDelayed(msg, 3000);
        } else {
            // TODO: The system bars are NOT visible. Make any desired

            }
        }
    }
});

The disadvantage with this approach is the first touch event could not be used by your app. I think you have to use other approaches like WindowManager.LayoutParams or Immersive Fullscreen Mode in that case.

Upvotes: 7

Related Questions