Режим Sticky immersive отключен после показа мягкой клавиатуры

У меня есть приложение, которое должно быть полноэкранным большую часть времени. Я знаю, что если отображается предупреждение или другое окно, над верхней частью окна активности, полный экран временно удаляется. К сожалению, когда мягкая клавиатура отображается для EditText или что-то, когда пользователь закончил с клавиатурой, полноэкранный режим погружения не восстанавливается.

есть идеи, как этого можно достичь?

4 ответов


принято от этот пример приложения на Google, вам нужно добавить это в конец вашей деятельности, перед последней конечной скобкой:

@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);
}

и вы должны быть хорошо. :)


Это нормальное поведение. Но вы можете исправить это в два шага :
1. Узнайте, когда клавиатура скрыта
2. Установите захватывающий полноэкранный режим (снова)

Шаг 1-немного сложнее. Вы можете проверить мой ответ здесь:
https://stackoverflow.com/a/27567074/2525452

Шаг 2 прост:

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
    );
}

Я предлагаю расширить AppCompatActivity в новый класс (ImmersiveAppCompatActivity). При этом любое действие, которое вы создаете с помощью этого класса, будет встроено в обработку иммерсивного режима.

если вы попытаетесь установить режим погружения слишком быстро после появления экранной клавиатуры, она не будет скрывать.

также обратите внимание, что обработчик был улучшен путем переключения на статический обработчик - это предотвратит утечки, если пользователь покинет действие до GUI скрытый.

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();
        }
    }
}

вот версия Котлина:

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)
    }
}

Теперь создайте свою активность, используя этот класс:

public class SettingsActivity extends ImmersiveAppCompatActivity {

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

я протестировал это в Android 5.1 и 7.0 для работы в полноэкранном приложении, которое не имеет панели действий.

кроме того, если вы используете клавиатуру в EditText быть в курсе imeOptions. В ландшафтном режиме вы можете получить странное поведение редактирования полного экрана. Это можно отключить, установив флаги imeOptions, которые содержатся в класс 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


я помещаю этот код в onCreate () наблюдатель изменения макета

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);
    }