How to adjust dialog layout when soft keyboard appears using the latest WindowInset API

12.3k views Asked by At

Question:

How to use the latest WindowInset API to adjust space betweeen my dialog and softkeyboard?


I have a BottomSheetDialog with some EditText. The default animation will show the soft keyboard right below my EditText which will cover my save button. After doing some research, I added this line into my BottomSheetDialog fragment

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

And it worked (as the picture is shown down below)!

This is what I wanted

But apparently SOFT_INPUT_ADJUST_RESIZE is deprecated.

   * @deprecated Call {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false} and
   * install an {@link OnApplyWindowInsetsListener} on your root content view that fits insets
   * of type {@link Type#ime()}.

And I couldn't figure out how to use the new OnApplyWindowInsetsListener to achieve the same effect. Here is my current BottomSheetDialog fragment:

public class BottomSheetDialog extends BottomSheetDialogFragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

//      Adding this line works, but it's deprecated in API 30
//      getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
      
        getDialog().getWindow().setDecorFitsSystemWindows(false);
        view = inflater.inflate(R.layout.fragment_bottom_dialog_cash, container, false);
        view.setOnApplyWindowInsetsListener((v, insets) -> {
            Log.d("dialog", "onCreateView: ");
            Insets imeInsets = insets.getInsets(WindowInsets.Type.ime());
            v.setPadding(0,0,0,imeInsets.bottom);
            return insets;
        });
        return view;
    }

I use an onclicklistener in another fragment to show this dialog. Code in Another fragment

    @Override
    public void onItemClick(int position) {
        BottomSheetDialog dialog = new BottomSheetDialog();
        dialog.show(getParentFragmentManager(), "BottomSheetDialog");
    }

In fact, the log indicates that the listener is never triggered when the soft keyboard pop up. FYI, I'm following this video and this blog.

3

There are 3 answers

0
JosephW On

After more research, I find out that if I use viewBinding and replace view with bind.getRoot(), then everything works fine. I'm not sure why (maybe I should use in onViewCreated instead of onCreateView ?) but the code should be helpful for people having the same issue.

// NOTE: you have to set this in the activity instead of fragment.
getWindow().setDecorFitsSystemWindows(false);

// Only work with API30 or above!
bind.getRoot().setOnApplyWindowInsetsListener((v, insets) -> { 
    imeHeight = insets.getInsets(WindowInsets.Type.ime()).bottom;
    bind.getRoot().setPadding(0, 0, 0, imeHeight);
    return insets;
});

One thing to be noticed is that setDecorFitsSystemWindows(false) means the app (you) are responsible for all the system windows includes the status bar and navigation bar.

I also find the tutorials linked down below are very useful, please check if you wanna know more about windowInsets and new animation callback.

New WindowInsets APIs for checking the keyboard (IME) visibility and size

Window Insets and Keyboard Animations Tutorial for Android 11

0
isles1217 On

The only thing that seemed to do the trick for me was setting the style of the BottomSheetDialog to use the following:

<style name="BottomSheetDialogTheme" parent="Theme.MaterialComponents.Light.BottomSheetDialog">
  <item name="android:windowIsFloating">false</item>
  <item name="android:windowSoftInputMode">adjustResize|stateVisible</item>
</style>
0
Zakhar Rodionov On

Compat Version

WindowCompat.setDecorFitsSystemWindows(window, false)
ViewCompat.setOnApplyWindowInsetsListener(rootView()) { _, insets ->
    val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
    rootView().setPadding(0, 0, 0, imeHeight)
    insets
}

Or use Insetter library

 WindowCompat.setDecorFitsSystemWindows(window, false)
 rootView().applyInsetter {
        type(ime = true) {
            padding()
        }
    }