web-dev-qa-db-fra.com

Le mode immersif collant est désactivé après l'affichage du clavier virtuel

J'ai une application qui doit être en plein écran la plupart du temps. Je sais que si une alerte est affichée ou si une autre fenêtre est affichée, en haut de la fenêtre d'activité, le plein écran est temporairement supprimé. Malheureusement, lorsqu'un clavier virtuel est affiché pour un objet EditText ou quelque chose du genre, lorsque l'utilisateur en a fini avec le clavier, le mode immersif plein écran n'est pas restauré.

Une idée de comment cela peut être réalisé?

19
jomalden

Extrait de cet exemple d'application de Google , vous devez l'ajouter à la fin de votre activité, avant la dernière parenthèse:

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    // When the window loses focus (e.g. the action overflow is shown),
    // cancel any pending hide action. When the window gains focus,
    // hide the system UI.
    if (hasFocus) {
        delayedHide(300);
    } else {
        mHideHandler.removeMessages(0);
    }
}

private void hideSystemUI() {
    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_HIDE_NAVIGATION | 
        View.SYSTEM_UI_FLAG_FULLSCREEN | 
        View.SYSTEM_UI_FLAG_LOW_PROFILE | 
        View.SYSTEM_UI_FLAG_IMMERSIVE
    );
}

private void showSystemUI() {
    getWindow().getDecorView().setSystemUiVisibility(
        View.SYSTEM_UI_FLAG_LAYOUT_STABLE | 
        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | 
        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    );
}

private final Handler mHideHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        hideSystemUI();
    }
};

private void delayedHide(int delayMillis) {
    mHideHandler.removeMessages(0);
    mHideHandler.sendEmptyMessageDelayed(0, delayMillis);
}

Et tu devrais être bon. :)

11
r3pwn

Je suggère d'étendre AppCompatActivity dans une nouvelle classe (ImmersiveAppCompatActivity). En faisant cela, toute activité que vous créez en utilisant cette classe aura une gestion intégrée du mode immersif. 

Si vous essayez de définir le mode immersif trop rapidement après l'apparition du clavier logiciel, celui-ci ne se cache pas.

Notez également que le gestionnaire a été amélioré en passant à un gestionnaire statique. Cela évitera les fuites si l'utilisateur quitte l'activité avant que l'interface graphique ne soit masquée.

public abstract class ImmersiveAppCompatActivity extends AppCompatActivity {
    private HideHandler mHideHandler;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // create a handler to set immersive mode on a delay
        mHideHandler = new HideHandler(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        setToImmersiveMode();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if(hasFocus) {
            mHideHandler.removeMessages(0);
            mHideHandler.sendEmptyMessageDelayed(0, 300);
        }
        else mHideHandler.removeMessages(0);
    }

    private void setToImmersiveMode() {
        // set to immersive
        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_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    }

    private static class HideHandler extends Handler {
        private final WeakReference<ImmersiveAppCompatActivity> mActivity;

        HideHandler(ImmersiveAppCompatActivity activity) {
            mActivity = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            ImmersiveAppCompatActivity activity = mActivity.get();
            if(activity != null) activity.setToImmersiveMode();
        }
    }
}

Voici la version Kotlin:

abstract class ImmersiveAppCompatActivity : AppCompatActivity() {
    override fun onResume() {
        super.onResume()

        setToImmersiveMode()
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)

        val runnable = Runnable { setToImmersiveMode() }

        val handler = Handler(Looper.getMainLooper())
        handler.postDelayed(runnable, 300)
    }

    private fun setToImmersiveMode() {
        window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_FULLSCREEN
                or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
    }
}

Maintenant, créez votre activité en utilisant cette classe:

public class SettingsActivity extends ImmersiveAppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getFragmentManager().beginTransaction().replace(Android.R.id.content, new SettingsFragment()).commit();
    }
}

J'ai testé cela dans Android 5.1 et 7.0 pour fonctionner dans une application plein écran sans barre d'action.

De plus, si vous utilisez le clavier dans un EditText, tenez compte des options imeOptions. En mode paysage, vous pouvez obtenir un comportement étrange d'édition en plein écran. Cela peut être désactivé en définissant les indicateurs imeOptions contenus dans la classe EditorInfo:

<EditText
    Android:layout_width="@dimen/pin_width"
    Android:layout_height="wrap_content"
    Android:inputType="numberPassword"
    Android:imeOptions="flagNoExtractUi"
    Android:ems="10"
    Android:id="@+id/editTextPIN"
    Android:textSize="@dimen/pin_large_text_size"/>

https://developer.Android.com/reference/Android/view/inputmethod/EditorInfo.html

2
Letdown

C'est le comportement normal. Mais vous pouvez le réparer en deux étapes:
1. Savoir quand le clavier est caché
2. Réglez le mode plein écran immersif (à nouveau)

L'étape 1 est un peu délicate. Vous pouvez consulter ma réponse ici:
https://stackoverflow.com/a/27567074/2525452

L'étape 2 est simple:

public static void setImmersiveMode( Activity activity )
{
    // Get the Activity's content View
    ViewGroup content = (ViewGroup) activity.findViewById( Android.R.id.content );
    //
    // Set the immersive mode flags at the content View
    content.setSystemUiVisibility(
        View.SYSTEM_UI_FLAG_IMMERSIVE |
        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
        View.SYSTEM_UI_FLAG_FULLSCREEN |
        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
    );
}
1
fies

Je mets ce code sur onCreate () Observer les changements de mise en page

getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {

        Rect rect = new Rect();
        getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
        int screenHeight = getWindow().getDecorView().getRootView().getHeight();

        int keyboardHeight = screenHeight - rect.bottom;

        if (keyboardHeight > screenHeight * 0.15) {
             setToImmersiveMode();
        }
    }
});


private void setToImmersiveMode() {
        // set to immersive
        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_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    }
0
NOT_A_PROGRAMMER