Навигация в иммерсивном режиме становится липкой после нажатия громкости или свертывания-восстановления.

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

}

После первого запуска

После первого запуска

После нажатия кнопок громкости или после двойного нажатия последних приложений

введите здесь описание изображения

Я видел, что в приложении QuickPic нет этой ошибки. Интересно, как они это пропустили.


person Yaroslav Mytkalyk    schedule 16.01.2014    source источник


Ответы (3)


У меня работает следующий код:

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

И вызвал слушателя по методам onCreate и onResume:

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

@Override
public void onResume() {
    super.onResume();
    updateUI();
}
person emjee    schedule 22.01.2014
comment
Этот фикс по-прежнему имеет эффект черной полосы при изменении громкости? - person Peter Brooks; 28.03.2014
comment
@Peter Brooks Я пробовал это, и хотя он исправляет иммерсивный режим, панель навигации действительно становится черной на секунду, когда она видна. - person Rudey; 30.05.2014
comment
у меня не работает в случае появления клавиатуры - person Menna-Allah Sami; 22.02.2015
comment
он все еще отображается на секунду, но, по крайней мере, мой контент не перемещается, так что это мне очень помогло :) - person OlivierM; 01.03.2015
comment
Спасибо это помогло мне - person Aayushi; 03.03.2015
comment
Пришлось вызывать его в onResume. Спасибо - person Diljeet; 05.07.2015
comment
Изысканный. Спасибо, джентльмен - person aProperFox; 14.10.2015
comment
Отлично работает на Android N. Спасибо! - person Denys Vitali; 25.04.2016
comment
Соответствующая документация: developer.android.com/training/system-ui/visibility.html. - person ajh158; 08.06.2016
comment
setOnSystemUiVisibilityChangeListener требует, чтобы для fitsSystemWindows было установлено значение false, чтобы работать - person MiguelSlv; 12.01.2017

Мое решение состоит в том, чтобы установить флаги UI-Visibility в трех местах:

  1. При получении фокуса
  2. В onResume
  3. В прослушивателе OnSystemUiVisibilityChangeListener

Третий решил мою проблему. Остальные, может, и не нужны, но я их оставил. Вот как это выглядит:

  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() вызывается в onCreate().

person Chris    schedule 02.06.2014
comment
Одного третьего варианта недостаточно. После долгих испытаний я заметил, что OnSystemUiVisibilityChangeListener не всегда срабатывает. Я решил это, добавив первый вариант, но, чтобы быть уверенным, я также реализовал второй вариант. Хороший ответ :) - person Rudey; 05.06.2014
comment
Вы имеете в виду под опцией один вызов в onwindowfocuschanged? - person Menna-Allah Sami; 22.02.2015
comment
Фу, разработка под Android иногда действительно ужасна. - person Dean Wild; 02.03.2016
comment
Очень красиво, покрывает большинство моих проблем - person Gilian; 15.06.2016
comment
Когда отображается диалоговое окно или Spinner, у него есть собственное окно, поэтому setSystemUiVisilityMode of Activity не имеет эффекта, и пользовательский интерфейс навигации по-прежнему отображается. - person activity; 28.03.2018
comment
Должно быть 3 варианта :D - person CarLoOSX; 14.03.2019

У меня была такая же проблема, и я решил ее с помощью простого обходного пути. Хотя я не мог найти теоретическую причину этого обходного пути, но он все равно сработал для меня.

Похоже, что при нажатии кнопки громкости «флаги», связанные с «режимом погружения», сбрасываются. И я думаю поэтому иммерсивный режим отключается и иммерсивный режим не восстанавливается автоматически.

Поэтому я попытался установить «флаги» после нажатия кнопки громкости с «запускаемым» объектом.

Итак, это работает так:

режим погружения -> нажата кнопка громкости (флаги очищены) -> через 500 мс исполняемый объект снова устанавливает флаги -> режим погружения восстановлен

<сильный>1. Сначала определите исполняемый объект, чтобы установить флаги

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. Отправьте исполняемый объект с некоторой задержкой в ​​обработчик при нажатии кнопки громкости

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

Я просто задержал его на 500 мс без причины, это не важно.

<сильный>3. Базовый код для иммерсивного режима с запускаемым объектом

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

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

Он отлично работал в моем приложении.

Итак, когда я нажимаю кнопку громкости, режим погружения отключается и появляется качелька громкости.

через несколько секунд качелька громкости исчезает, а также строка состояния и панель навигации.

Надеюсь, эта работа для вас.

person Sangseok    schedule 21.01.2014
comment
Спасибо, работает отлично, это должно быть принято как лучший ответ! - person Tony Ceralva; 21.05.2014
comment
У меня была проблема даже с этим отложенным исправлением при переключении между приложениями. Мне помог вызов setSystemUiVisibility дважды: без SYSTEM_UI_FLAG_IMMERSIVE_STICKY, а затем снова с SYSTEM_UI_FLAG_IMMERSIVE_STICKY. Подробнее: vitiy.info/ - person Victor Laskin; 19.06.2014
comment
Вау, это действительно помогло. Отказ от клавиатуры не всегда избавлял нас от клавиатуры. И ожидание уведомления об изменении было немного более эффективным, но на старых устройствах все еще есть какое-то состояние гонки, но простое подключение к изменению видимости избавило от панели навигации, когда пришло время ее скрыть. Спасибо! - person Hunter-Orionnoir; 14.05.2016
comment
Спасибо. Я показываю растровое изображение ImageView в полноэкранном режиме в новом фрагменте при нажатии. Однако после полноэкранного режима внизу появилось пустое пространство размером со строку состояния. Использование View # post (Runnable) в onCreateView () работает для меня. - person Lym Zoy; 01.01.2017
comment
Это решение действительно работает и должно быть принятым ответом! Спасибо за потрясающую работу - person Bhavik Mehta; 21.12.2017