31 октября 2013 года Google представили новую версию ОС Android 4.4 KitKat, в которой появилось очень много интересных функций для разработчиков. Одна из этих функций — Immersive Mode (режим погружения). Режим погружения — это режим, в котором ваша программа показывается пользователю на весь экран, при этом не видны любые системные панели, в том числе и панель навигации (та, что с кнопкой Back). Этот режим сделали именно для того, чтобы пользователь мог полностью погрузится в контент, с которым он в данный момент взаимодействует, будь то читалка электронных книг или игра, в которой пользователь постоянно взаимодействует с экраном. Как же тогда пользователю увидеть системные панели в таком режиме, чтобы, например, выйти из приложения? Очень просто, команда Android для этого придумали очень простое решение, пользователю достаточно сделать свайп от верхнего или нижнего края экрана по направлению к центру экрана или нажать на любое место вне системных панелей. Кстати, при первом запуске приложения пользователю автоматически покажется системное сообщение о том, как использовать приложение в полноэкранном режиме.
Также вы могли подумать, что есть другая проблема использования этого режима. Например, пользователь запустил программу для рисования и хочет нарисовать линию от края экрана и как же так, неужели ему в этом случае отобразится системная панель. Да, но при этом приложение также будет получать сообщения от нажатий на экран и будет рисовать линию, системные панели же появятся с полупрозрачным фоном и не станут для пользователя раздражающим фактором.
А как же снова попасть в полноэкранный режим? У пользователя есть два варианта, нажать на любой контент вне системных панелей, либо подождать некоторое время, чтобы панели скрылись автоматически. Все эти варианты программист может предусмотреть в своем приложении. Для этого команда Android сделала так, чтобы оба этих способа взаимодействия с Immersive Mode можно было реализовать очень просто. Есть два типа режима погружения — обычный и sticky («липкий»). В обычном режиме программисту надо самому решать, когда скрывать панели, а в sticky-режиме системные панели будут скрываться автоматически. Для установки обоих типов режима погружения необходимо воспользоваться методом setSystemUiVisibility(), только передать в параметры разные флаги. Вызывать этот метод необходимо у так называемого Decor View, который представляет собой внешний вид окна Activity со всем его оформлением и содержимым. Ссылку на этот View получить очень просто.
mDecorView = getWindow().getDecorView();
Давайте рассмотрим оба типа режима погружения поподробнее.
Обычный Immersive Mode
Для установки обычного режима используется флаг SYSTEM_UI_FLAG_IMMERSIVE в качестве параметра метода setSystemUiVisibility().
Лучше всего для работы с обычным immersive-режимом сделать два простых метода, которые будут показывать и скрывать системные панели соответственно.
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);
}
Для тех случаев, когда показывать и скрывать системные панели вам нужно по нажатию на контент (contentView), необходимо использовать следующий код. Это может пригодится, например, при просмотре видео, как в YouTube, где вам не нужно взаимодействовать с контентом во время его просмотра.
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);
}
});
Если при этом у вас в приложении есть какие-то свои панели (controlsView), которые тоже надо скрыть вместе с системными, вы это также можете просто сделать, написав следующий код. Тут скрытие и появление происходит с использованием анимации альфа-канала и позиции по Y вашей панели.
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());
}
});
Если при запуске приложения вы хотите показать пользователю, что у приложения есть панели, а потом их скрыть через некоторое время, это тоже довольно просто делается.
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);
}
Также иногда может потребоваться показывать панель, когда окно получает фокус, например, после возвращения из вызванного диалога. Такой вариант можно обработать следующим кодом.
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
delayedHide(INITIAL_HIDE_DELAY);
} else {
mHideHandler.removeMessages(0);
}
}
В этом случае панель покажется и потом исчезнет через заданное вами время.
Immersive Mode Sticky
Для установки sticky-режима используется флаг SYSTEM_UI_FLAG_IMMERSIVE_STICKY в качестве параметра метода setSystemUiVisibility().
Этот режим чрезвычайно прост. Если вам необходима ситуация, при которой системные панели будут скрываться, когда окно получает фокус или проходит некоторое время после появлении панелей, то этот режим для вас. Для включения этого режима вам необходимо установить для окна, когда оно находится в фокусе, флаг SYSTEM_UI_FLAG_IMMERSIVE_STICKY. В этом режиме, если окно теряет фокус, оно автоматически сбрасывается до состояния, в котором окно было до установки флага SYSTEM_UI_FLAG_IMMERSIVE_STICKY, то есть со всеми панелями. Как только окно получает фокус, панели опять исчезают через некоторое время и вам нет нужды программировать эту ситуацию вручную. Чтобы показать системные панели надо также, как и в обычном режиме, сделать свайп от краев экрана. Включение stick-режима делается простым куском кода.
@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);
}
}
P.S. В статьи использовались материалы видео от Roman Nurik. Код полных примеров от Романа по использованию этого режима можно скачать тут.
Автор: tum0rc0re