Immersive mode navigation becomes sticky after volume press or minimise-restore

后端 未结 3 1885
执念已碎
执念已碎 2020-11-28 04:14
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        this.getWindow().getDecorView().setSyste         


        
相关标签:
3条回答
  • 2020-11-28 04:55

    The following code works for me:

    public void updateUI() {
        final View decorView = getWindow().getDecorView();
        decorView.setOnSystemUiVisibilityChangeListener (new View.OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                    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);
                    }
                }
            });
    }
    

    And called the listener on onCreate and onResume methods:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        updateUI();
    }
    
    @Override
    public void onResume() {
        super.onResume();
        updateUI();
    }
    
    0 讨论(0)
  • 2020-11-28 04:58

    I had the same problem, and I solved it with a simple workaround. Even though I couldn't find the theoretical reason of this workaround, but it worked for me anyway.

    It seems like when a volume button is pressed, the 'flags' related to the 'immersive mode' are cleared. And I think that's why the immersive mode is disabled and the immersive mode is not restored automatically.

    Therefore, I tried to set the 'flags' after pressing the volume button with 'runnable' object.

    So, it works like this:

    immersive mode -> volume button pressed(flags cleared) -> 500ms later, the runnable object sets the flags again -> immersive mode restored

    1. First, define the runnable object to set the flags

    private Runnable decor_view_settings = new Runnable()
    {
        public void run() 
        {
            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
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
        }
    };
    

    2. Post the runnable object with some delay to a handler when a volume button is pressed

    private Handler mHandler = new Handler();
    

    ...

    @Override 
    public boolean onKeyDown(int keyCode, KeyEvent event) 
    {
        if(keyCode == KeyEvent.KEYCODE_BACK)
        {
            finish();
        }
        else if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP)
        {
            mHandler.postDelayed(decor_view_settings, 500);
        }
    
        return super.onKeyDown(keyCode, event);
    }
    

    I just delayed it for 500ms with no reason, it's not important.

    3. The basic code for immersive mode with runnable object

    @Override
    public void onWindowFocusChanged(boolean hasFocus) 
    {
        super.onWindowFocusChanged(hasFocus);
    
        if(hasFocus) 
        {
            mHandler.post(decor_view_settings);
        }
    }
    

    It worked perfectly on my app.

    So, when I press a volume button, the immersive mode is disabled and the volume rocker pops up.

    after a few seconds, the volume rocker disappears and so does the status bar and the navigation bar.

    Hope this work for you.

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

    My solution is to set the UI-Visibility flags in three places:

    1. When getting the focus
    2. In onResume
    3. In the OnSystemUiVisibilityChangeListener listener

    The third solved my problem. The others might not be needed, but I left them. This is what is looks like:

      private void setupMainWindowDisplayMode() {
        View decorView = setSystemUiVisilityMode();
        decorView.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
          @Override
          public void onSystemUiVisibilityChange(int visibility) {
            setSystemUiVisilityMode(); // Needed to avoid exiting immersive_sticky when keyboard is displayed
          }
        });
      }
    
      private View setSystemUiVisilityMode() {
        View decorView = getWindow().getDecorView();
        int options;
        options =
            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(options);
        return decorView;
      }
    

    setupMainWindowDisplayMode() gets called in onCreate().

    0 讨论(0)
提交回复
热议问题