web-dev-qa-db-fra.com

La navigation en mode immersif devient collante après avoir appuyé sur le volume ou minimisé-restauré

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        this.getWindow().getDecorView().setSystemUiVisibility(getSystemUiFlags());
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    private static int getSystemUiFlags() {
            return View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
    }

}

Après le premier démarrage

After first start

Après avoir appuyé deux fois sur les boutons de volume ou appuyé deux fois sur les applications récentes

enter image description here

J'ai vu que l'application QuickPic n'a pas ce bug. Je me demande comment ils l'ont omis.

28
Yaroslav Mytkalyk

Le code suivant fonctionne pour moi:

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);
                }
            }
        });
}

Et a appelé l'écouteur sur les méthodes onCreate et onResume:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    updateUI();
}

@Override
public void onResume() {
    super.onResume();
    updateUI();
}
55
emjee

Ma solution consiste à définir les drapeaux UI-Visibility à trois endroits:

  1. Lors de la mise au point
  2. Dans onResume
  3. Dans l'écouteur OnSystemUiVisibilityChangeListener

Le troisième a résolu mon problème. Les autres pourraient ne pas être nécessaires, mais je les ai laissés. Voici à quoi ça ressemble:

  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 () est appelé dans onCreate ().

21
Chris

J'ai eu le même problème et je l'ai résolu avec une solution de contournement simple. Même si je n'ai pas pu trouver la raison théorique de cette solution de contournement, mais cela a quand même fonctionné pour moi.

Il semble que lorsqu'une touche de volume est enfoncée, les "drapeaux" liés au "mode immersif" sont effacés. Et je pense que c'est pourquoi le mode immersif est désactivé et le mode immersif n'est pas restauré automatiquement.

Par conséquent, j'ai essayé de définir les "drapeaux" après avoir appuyé sur le bouton de volume avec l'objet "exécutable".

Donc, cela fonctionne comme ceci:

mode immersif -> bouton de volume enfoncé (drapeaux effacés) -> 500 ms plus tard, l'objet exécutable définit à nouveau les drapeaux -> mode immersif restauré

1. Tout d'abord, définissez l'objet exécutable pour définir les drapeaux

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. Publiez l'objet exécutable avec un certain retard à un gestionnaire quand un bouton de volume est pressé

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);
}

Je l'ai juste retardé de 500 ms sans raison, ce n'est pas important.

. Le code de base pour le mode immersif avec un objet exécutable

@Override
public void onWindowFocusChanged(boolean hasFocus) 
{
    super.onWindowFocusChanged(hasFocus);

    if(hasFocus) 
    {
        mHandler.post(decor_view_settings);
    }
}

Cela a parfaitement fonctionné sur mon application.

Ainsi, lorsque j'appuie sur un bouton de volume, le mode immersif est désactivé et la bascule de volume apparaît.

après quelques secondes, la bascule du volume disparaît, de même que la barre d'état et la barre de navigation.

J'espère que ce travail pour vous.

18
Sangseok