Jak zachować nowy tryb immersyjny, gdy moje działania wyświetlają niestandardowe okno dialogowe?
Używam poniższego kodu, aby utrzymać tryb immersyjny w oknach dialogowych, ale dzięki temu rozwiązaniu pasek nawigacyjny pojawia się na mniej niż sekundę po uruchomieniu mojego niestandardowego okna dialogowego, a następnie znika.
Poniższy film wyjaśnia problem lepiej (spójrz na dół ekranu, gdy pojawi się pasek NavBar): http://youtu.be/epnd5ghey8g
Jak uniknąć tego zachowania?
KOD
Ojciec wszystkich działań w mojej aplikacji:
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();
}
}
Wszystkie moje niestandardowe okna dialogowe wywołują tę metodę w swojej onCreate(. . .)
metodzie:
/**
* 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()
);
}
}
EDYCJA - ROZWIĄZANIE (podziękowania dla Beaver6813, spójrz na jego odpowiedź po więcej szczegółów):
Wszystkie moje niestandardowe okna dialogowe zastępują metodę show w ten sposób:
/**
* 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);
}
Odpowiedzi:
Po wielu badaniach tego problemu można było znaleźć hackerską poprawkę, która polegała na rozerwaniu klasy Dialog w celu znalezienia. Pasek nawigacji jest wyświetlany po dodaniu okna dialogowego do Menedżera okien, nawet jeśli ustawiono widoczność interfejsu użytkownika przed dodaniem go do menedżera. W przykładzie immersyjnym dla systemu Android stwierdzono, że:
Uważam, że właśnie to widzimy tutaj (że interakcja użytkownika jest wyzwalana, gdy do menedżera zostanie dodany nowy, możliwy do zaznaczenia widok okna).
Jak możemy to obejść? Spraw, aby okno dialogowe nie było fokusem, kiedy go tworzymy (abyśmy nie wyzwalali interakcji użytkownika), a następnie ustaw je jako aktywne po wyświetleniu.
Oczywiście nie jest to idealne rozwiązanie, ale wydaje się, że jest to błąd Androida, powinni sprawdzić, czy okno ma zestaw immersyjny.
Zaktualizowałem mój działający kod testowy (wybacz hacky bałagan) do Github . Przetestowałem na emulatorze Nexusa 5, prawdopodobnie wybuchnie z czymś mniejszym niż KitKat, ale służy tylko do weryfikacji koncepcji.
źródło
Dla twojej informacji, dzięki odpowiedzi @ Beaver6813, udało mi się to uruchomić za pomocą DialogFragment.
w metodzie onCreateView mojego DialogFragment, właśnie dodałem:
źródło
Jeśli chcesz użyć onCreateDialog () , wypróbuj tę klasę. U mnie działa całkiem nieźle ...
Aby wyświetlić okno dialogowe, wykonaj następujące czynności w swoim ćwiczeniu ...
źródło
Łącząc odpowiedzi tutaj, stworzyłem abstrakcyjną klasę, która działa we wszystkich przypadkach:
źródło
Działa to również w przypadku metody jazdy onDismiss fragmentu okna dialogowego. W ramach tej metody wywołaj metodę działania, do którego jest dołączona, ponownie ustaw flagi pełnego ekranu.
A w swojej aktywności dodaj tę metodę:
źródło
AlertDialog.Builder
i.setOnDismissListener()
Gdy tworzysz swój własny DialogFragment, musisz tylko zastąpić tę metodę.
źródło
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
okno dialogowe poWiem, że to stary post, ale moja odpowiedź może pomóc innym.
Poniżej znajduje się hacky poprawka dla efektu immersyjnego w dialogach:
źródło