Como mantenho o novo Modo Imersivo quando minhas atividades exibem uma caixa de diálogo personalizada?
Estou usando o código abaixo para manter o Modo Imersivo em Diálogos, mas com essa solução, a NavBar aparece por menos de um segundo quando eu inicio minha caixa de diálogo personalizada e depois desaparece.
O vídeo a seguir explica melhor o problema (observe a parte inferior da tela quando a NavBar aparecer): http://youtu.be/epnd5ghey8g
Como posso evitar esse comportamento?
CÓDIGO
O pai de todas as atividades em meu aplicativo:
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();
}
}
Todos os meus Diálogos personalizados chamam este método em seus onCreate(. . .)
métodos:
/**
* 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()
);
}
}
EDITAR - A SOLUÇÃO (obrigado a Beaver6813, veja a resposta dele para mais detalhes):
Todas as minhas caixas de diálogo personalizadas substituem o método show desta maneira:
/**
* 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);
}
Respostas:
Depois de muita pesquisa sobre o problema, há uma solução hacky para isso, que envolveu destruir a classe Dialog para encontrar. A barra de navegação é mostrada quando a janela de diálogo é adicionada ao Gerenciador de janelas, mesmo se você definir a visibilidade da IU antes de adicioná-la ao gerenciador. No exemplo do Android Immersive , é comentado que:
Acredito que é isso que estamos vendo aqui (que uma interação do usuário está sendo acionada quando uma nova visualização de janela focável é adicionada ao gerenciador).
Como podemos contornar isso? Torne a caixa de diálogo sem foco ao criá-la (para não acionar uma interação do usuário) e, em seguida, torne-a focalizável depois de exibida.
Claramente isso não é o ideal, mas parece ser um bug do Android, eles devem verificar se a janela tem um conjunto imersivo.
Eu atualizei meu código de teste de trabalho (perdoe a bagunça hacky) para Github . Eu testei no emulador Nexus 5, ele provavelmente irá explodir com qualquer coisa menos do que KitKat, mas é apenas para prova de conceito.
fonte
Para sua informação, graças à resposta de @ Beaver6813, consegui fazer isso funcionar usando DialogFragment.
no método onCreateView do meu DialogFragment, acabei de adicionar o seguinte:
fonte
Se você quiser usar onCreateDialog () , tente esta classe. Funciona muito bem para mim ...
Para mostrar a caixa de diálogo, faça o seguinte em sua atividade ...
fonte
Combinando as respostas aqui, fiz uma classe abstrata que funciona em todos os casos:
fonte
Isso também funciona sobre o método onDismiss de seu fragmento de diálogo. E dentro desse método, chame o método da atividade à qual ele está anexado novamente, defina os sinalizadores de tela inteira.
E em sua atividade adicione este método:
fonte
AlertDialog.Builder
e.setOnDismissListener()
Enquanto você está criando seu próprio DialogFragment, você só precisa substituir este método.
fonte
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
caixa de diálogo exibida depoisEu sei que esta é uma postagem antiga, mas minha resposta pode ajudar outras pessoas.
Abaixo está a correção de hacky para efeito imersivo em Diálogos:
fonte