Я столкнулся с проблемой, связанной с фрагментами, в более крупном проекте, над которым я работаю, и я создал минимальный проверяемый пример, чтобы объяснить его:
Пример настройки:
Пример проекта - это приложение без панели действий (тема имеет Theme.AppCompat.Light.NoActionBar
в качестве родителя), с targetSdkVersion 27
и minSdkVersion 23
.
Основным действием является AppCompatActivity
с android.support.v4.widget.DrawerLayout
в качестве корневого макета. Этот DrawerLayout имеет android:fitsSystemWindows="true"
, чтобы перекрывать строку состояния.
Внутри DrawerLayout
есть FrameLayout
, в котором будет android.support.v4.app.Fragment
. Фрагмент добавляется в интерфейс и в backstack при нажатии кнопки:
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragmentContent, fragment);
transaction.addToBackStack(fragment.getClass().getName());
transaction.commitAllowingStateLoss();
Этот фрагмент показывает кнопку, которая удаляет фрагмент, вызывая onBackPressed
для действия.
Пока что поведение приложения нормальное: фрагмент добавляется при нажатии кнопки на макете активности, а затем удаляется при нажатии кнопки на макете фрагмента.
Проблема:
Я добавляю в действие новую кнопку, которая при касании устанавливает цвет строки состояния на белый, а SystemUiVisibility
для вида оформления окна - на SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
:
Window window = getWindow();
window.setStatusBarColor(ContextCompat.getColor(this, android.R.color.white));
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
После нажатия этой кнопки строка состояния, как и ожидалось, отображается черным текстом на белом фоне.
Неожиданная часть заключается в том, что после этого изменения фрагмент больше не отображается в интерфейсе, когда я нажимаю кнопку, которая добавляет его .
Фрагмент по-прежнему помещается в backstack, поскольку нажатие клавиши возврата системы не сразу завершает действие, а удаляет фрагмент. Я подтвердил это, добавив операторы log в методы фрагмента onResume
и onPause
и убедившись, что они вызываются, когда фрагмент добавляется и удаляется из backstack.
Расследование:
Я пробовал несколько обходных путей и исследовал несколько возможных причин.
Что мне удалось найти:
Проблема возникает только для некоторых конфигураций приложения. Все это должно быть верно, чтобы проблема проявилась:
- Тема приложения имеет
Theme.AppCompat.Light.NoActionBar
в качестве родителя.
- Мероприятие имеет в качестве корневого макета
android.support.v4.widget.DrawerLayout
.
-
DrawerLayout
имеет android:fitsSystemWindows="true"
.
- Должны быть установлены как цвет строки состояния, так и
SystemUiVisibility
для вида оформления окна.
-
SystemUiVisibility
для вида декорации окна должно быть установлено на SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
.
& EnSP;
Они могут показаться произвольными, но они нужны мне в моем приложении, чтобы интерфейс не отображал панель действий, предоставлял полноэкранное боковое меню и адаптировал цвет строки состояния к цвету каждого макета, который я показываю.
& EnSP;
Я рассмотрел код для DrawerLayout
, как возможный источник понимания этого вопроса. Я даже создал локальную копию компонента, чтобы можно было закомментировать различные разделы и добавить операторы журнала для отслеживания поведения.
Мне удалось отследить проблему до DrawerLayout
, установив для SystemUiVisibility
значение SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
.
Когда эти флаги установлены, OnApplyWindowInsetsListener
вызывается, когда я устанавливаю белый цвет строки состояния, а SystemUiVisibility
для вида декорации окна - SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
.
В свою очередь, этот слушатель вызывает метод setChildInsets
, который в конце вызывает requestLayout()
для DrawerLayout
.
Этот запрос макета является последним, полученным DrawerLayout
. С этого момента его метод onLayout
больше не вызывается при установке цвета строки состояния и SystemUiVisibility
для представления оформления окна, а также при добавлении фрагмента. Ни метод onMeasure
, ни OnApplyWindowInsetsListener
никогда не будут вызваны после этой точки. Представления фрагментов больше не отображаются, и их размер показывает, что он остается равным 0.
код:
Вы можете скачать пример проекта .
Вопрос (ы):
Что вызывает это, как и почему? Имеет ли он какое-либо отношение к DrawerLayout
напрямую или его поведение является лишь следствием, вызванным чем-то другим?
Почему это происходит только в том случае, если в приложении нет панели действий и когда SystemUiVisibility
для представления оформления окна установлено только на SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
?