0

The problem is that the FAB does not stay above the keyboard when using this flag:

this.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

I tried :

android:fitsSystemWindows="true"

It works but it removes the SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN effect.

android:windowSoftInputMode="adjustResize"

It does not work.

this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

It also does not work

Any sugestion ?

Greelings
  • 4,964
  • 7
  • 34
  • 70

1 Answers1

0

I just found a simple and reliable solution if you are using the system UI approach (https://developer.android.com/training/system-ui/immersive.html).

It works in the case when you are using View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, e.g. if you are using CoordinatorLayout.

It won't work for WindowManager.LayoutParams.FLAG_FULLSCREEN (The one you can also set in theme with android:windowFullscreen), but you can achieve similar effect with SYSTEM_UI_FLAG_LAYOUT_STABLE (which "has the same visual effect" according to the docs) and this solution should work again.

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION /* If you want to hide navigation */ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE)

I've tested it on my device running Marshmallow.

The key is that soft keyboards are also one of the system windows (such as status bar and navigation bar), so the WindowInsets dispatched by system contains accurate and reliable information about it.

For the use case such as in DrawerLayout where we are trying to draw behind the status bar, We can create a layout that ignores only the top inset, and applies the bottom inset which accounts for the soft keyboard.

Here is my custom FrameLayout:

/**
 * Implements an effect similar to {@code android:fitsSystemWindows="true"} on Lollipop or higher,
 * except ignoring the top system window inset. {@code android:fitsSystemWindows="true"} does not
 * and should not be set on this layout.
 */
public class FitsSystemWindowsExceptTopFrameLayout extends FrameLayout {

    public FitsSystemWindowsExceptTopFrameLayout(Context context) {
        super(context);
    }

    public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
                                                 int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
                                                 int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(),
                    insets.getSystemWindowInsetBottom());
            return insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(), 0, 0);
        } else {
            return super.onApplyWindowInsets(insets);
        }
    }
}

And to use it:

<com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Your original layout here -->
</com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout>

The credits go to : @Hai Zhang

Greelings
  • 4,964
  • 7
  • 34
  • 70