问题
I have an app that needs to be full screen most of the time. I know that if an alert is shown or other window is displayed, over the top of the activity window, full screen is temporarily removed. Unfortunately, when a soft keyboard is shown for an EditText or something, when the user has finished with the keyboard, full screen immersive mode is not restored.
Any idea how this can be achieved?
回答1:
Taken from this sample app by Google, you need to append this to the end of your activity, before the last end bracket:
@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);
}
And you should be good. :)
回答2:
I put this code at onCreate() observer the layout changes
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);
}
回答3:
I suggest extending AppCompatActivity into a new class (ImmersiveAppCompatActivity). By doing this, any activity that you create using this class will have built in handling of immersive mode.
If you try and set immersive mode too quickly after the soft keyboard has appeared, it will not hide.
Also note that the handler has been improved by switching to a static handler - this will prevent leaks if the user leaves the activity before the GUI is hidden.
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();
}
}
}
Here's the Kotlin version:
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)
}
}
Now, create your activity using this class:
public class SettingsActivity extends ImmersiveAppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
}
}
I've tested this in Android 5.1 and 7.0 to work in a full screen app that has no action bar.
Additionally, if you using the keyboard in an EditText be aware of the imeOptions. In landscape mode you can get strange full screen editing behavior. This can be disabled by setting imeOptions flags which are contained in the class 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
回答4:
This is the normal behaviour. But you can fix it in two steps :
1. Find out when the keyboard is hidden
2. Set the immersive fullscreen mode (again)
Step 1 is a little bit tricky. You can check out my answer here:
https://stackoverflow.com/a/27567074/2525452
Step 2 is 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
);
}
来源:https://stackoverflow.com/questions/24187728/sticky-immersive-mode-disabled-after-soft-keyboard-shown