Как мне поддерживать новый режим погружения, когда мои действия отображают настраиваемый диалог?
Я использую приведенный ниже код для поддержания иммерсивного режима в диалогах, но с этим решением панель навигации появляется менее чем на секунду, когда я запускаю свой собственный диалог, а затем исчезает.
Следующее видео лучше объясняет проблему (посмотрите на нижнюю часть экрана, когда появится NavBar): http://youtu.be/epnd5ghey8g
Как мне избежать такого поведения?
КОД
Отец всех активностей в моем приложении:
public abstract class ImmersiveActivity extends Activity {
@SuppressLint("NewApi")
private void disableImmersiveMode() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_FULLSCREEN
);
}
}
@SuppressLint("NewApi")
private void enableImmersiveMode() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
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_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
);
}
}
/**
* Set the Immersive mode or not according to its state in the settings:
* enabled or not.
*/
protected void updateSystemUiVisibility() {
// Retrieve if the Immersive mode is enabled or not.
boolean enabled = getSharedPreferences(Util.PREF_NAME, 0).getBoolean(
"immersive_mode_enabled", true);
if (enabled) enableImmersiveMode();
else disableImmersiveMode();
}
@Override
public void onResume() {
super.onResume();
updateSystemUiVisibility();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
updateSystemUiVisibility();
}
}
Все мои настраиваемые диалоги вызывают этот метод в своем onCreate(. . .)
методе:
/**
* Copy the visibility of the Activity that has started the dialog {@link mActivity}. If the
* activity is in Immersive mode the dialog will be in Immersive mode too and vice versa.
*/
@SuppressLint("NewApi")
private void copySystemUiVisibility() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
getWindow().getDecorView().setSystemUiVisibility(
mActivity.getWindow().getDecorView().getSystemUiVisibility()
);
}
}
РЕДАКТИРОВАТЬ - РЕШЕНИЕ (спасибо Beaver6813, подробнее см. Его ответ):
Все мои настраиваемые диалоги переопределяют метод show следующим образом:
/**
* An hack used to show the dialogs in Immersive Mode (that is with the NavBar hidden). To
* obtain this, the method makes the dialog not focusable before showing it, change the UI
* visibility of the window like the owner activity of the dialog and then (after showing it)
* makes the dialog focusable again.
*/
@Override
public void show() {
// Set the dialog to not focusable.
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
copySystemUiVisibility();
// Show the dialog with NavBar hidden.
super.show();
// Set the dialog to focusable again.
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
}
Ответы:
После долгого изучения проблемы для этой проблемы было разработано хакерское исправление, которое включало разрушение класса Dialog для поиска. Панель навигации отображается, когда диалоговое окно добавляется в диспетчер окон, даже если вы установили видимость пользовательского интерфейса перед добавлением его в диспетчер. В примере с Android Immersive сказано, что:
Я считаю, что это то, что мы здесь наблюдаем (что взаимодействие с пользователем запускается, когда в диспетчер добавляется новое, настраиваемое оконное представление).
Как мы можем обойти это? Сделайте диалог нефокусируемым, когда мы его создаем (чтобы мы не запускали взаимодействие с пользователем), а затем сделайте его фокусируемым после его отображения.
Ясно, что это не идеально, но, похоже, это ошибка Android, они должны проверить, есть ли у Window иммерсивный набор.
Я обновил свой рабочий тестовый код (простите за хакерский беспорядок) на Github . Я тестировал эмулятор Nexus 5, он, вероятно, взорвется с чем-то меньшим, чем KitKat, но это только для проверки концепции.
источник
Для вашей информации, благодаря ответу @ Beaver6813, мне удалось заставить это работать с помощью DialogFragment.
в методе onCreateView моего DialogFragment я только что добавил следующее:
источник
Если вы хотите использовать onCreateDialog () , попробуйте этот класс. У меня это работает очень хорошо ...
Чтобы отобразить диалоговое окно, сделайте в своей деятельности следующее ...
источник
Объединив ответы здесь, я создал абстрактный класс, который работает во всех случаях:
источник
Это также работает поверх метода onDismiss фрагмента вашего диалога. И внутри этого метода вызовите метод действия, к которому он прикреплен, чтобы снова установить флаги полноэкранного режима.
И в своей деятельности добавьте этот метод:
источник
AlertDialog.Builder
и.setOnDismissListener()
Когда вы создаете свой собственный DialogFragment, вам нужно только переопределить этот метод.
источник
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
показанный диалог послеЯ знаю, что это старый пост, но мой ответ может помочь другим.
Ниже приведено хакерское исправление для эффекта погружения в диалогах:
источник