Освой Android играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

WindowInsets и fitsSystemWindows

Любая активность размещается в специальном контейнере и пользователь видит её вместе с системными элементами - строкой состояния, панелью навигации. Всё вместе это контролируется классом Window. Но иногда требуется изменить стандартное поведение. Самый простой пример - игры в полноэкранном режиме, когда мы хотим скрыть все лишние элементы с экрана. Другой вариант - полноэкранный режим, но системные элементы накладываются поверх игры. Ещё один вариант - динамическое изменение, когда пользователь начинает прокручивать список вверх, то системная строка состояния исчезает, а при прокрутке вниз снова появляется.

Любая активность может получить доступ к окну Window через метод Activity#getWindow().


Window window = this.getWindow();
System.out.println(window.getClass().getSimpleName()); // PhoneWindow

Аналогично класс Dialog имеет своё окно Dialog#getWindow().

В свою очередь окно содержит всю необходимую информацию о размерах системных элементов и подстраивает все дочерние элементы (вашу активность), чтобы не было нигде зазоров или наложений друг на друга. Реализуется взаимное расположение при помощи специальных отступов Inset.

Поведение Window в разных версиях Android менялась. До KitKat была упрощённая версия не учитывала системные элементы управления. Доступ к ним осуществлялся через метод setSystemUiVisibility(). Также было множество флагов настроек: SYSTEM_UI_FLAG_VISIBLE, SYSTEM_UI_FLAG_FULLSCREEN и другие.

Начиная с KitKat, Android стала поддерживать полупрозрачные системные панели. Появились атрибуты androd:windowTranslucentStatus, android:windowsTranslucentNavigation.

В Lollipop происходит дальнейшая интеграция, системные элементы входят в состав Window и появилась возможность управлять фоном через android:windowDrawsSystemBarBackgrounds.

Мы можем узнать цвета системных элементов.


ImageView image = findViewById(R.id.imageView);

Window window = this.getWindow();
int navigationColor = window.getNavigationBarColor();
int statusBarColor = window.getStatusBarColor();
image.setBackgroundColor(statusBarColor);

android:fitsSystemWindows="true"

Данный флаг использовался для этой же цели. Сейчас в документации указано, что флаг считается устаревшим с версии API 20.

Данный флаг не будет иметь значения для многих видов макетов типа LinearLayout, FrameLayout. Но есть несколько видов макетов, к которым флаг применить можно. К таким макетам относятся DrawerLayout, CoordinatorLayout, AppBarLayout, CollapsingToolbarLayout, NavigationView.

Лучше вызывать метод onApplyWindowInsets().

Что делать не надо - вручную прописывать размеры строки состояния в ресурсах. Каждое устройство и каждая версия могут иметь свои размеры системных компонентов и ваша попытка видоизменить размеры приведёт к некрасивым последствиям в виде наслоений разных частей компонентов.

Для решения проблемы используйте методы getSystemWindowInsetLeft(), getSystemWindowInsetTop(), getSystemWindowInsetRight(), getSystemWindowInsetBottom() класса WindowInsets/WindowInsetsCompat.

При разработке собственного компонента можете использовать код:


// Kotlin
myView.setOnApplyWindowInsetListener{view, insets ->
    // Ваш код для обработки отступов
	...
	val statusBarSize = insets.systemWindowInsetTop
	
	return insets.consumeSystemWindowInsets()
}

Как уже упоминалось выше, отступы не работают с некоторыми видами макетов. Вы можете переопределить поведение макета, наследуясь от основного макета и переопределяя метод.


// Kotlin
class CustomLayout : LinearLayout {
	override fun onApplyWindowInsets(
	    insets: WindowInsets): WindowInsets {
			// Ваш код для обработки отступов
	        ...
			
	 	    return insets.consumeSystemWindowInsets()
		}
}

BottomNavigationView

Как работать с нижней частью экрана рассказано в статье WindowInsets — Listeners to layouts (12 Apr 2019).

Дополнительное чтение

droidcon NYC 2017 - Becoming a master window fitter🔧 - YouTube

Реклама