Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 983
JosephW Avatar asked Nov 21 '20 20:11

JosephW


People also ask

How do you move the layout up when the soft keyboard is shown Android fragment?

Set fitsSystemWindows = "false" and set android:windowSoftInputMode="adjustResize" in manifest file. Show activity on this post. I have used like this to show the soft keyboard programatically and this is worked for me to prevent the auto resize of the screen while launching the keyboard.

How do I prevent the soft keyboard from pushing my view up in fragment?

Setting android:isScrollContainer = "false" inside the ScrollView worked for me. According to the documentation, settings "isScrollContainer" to true means that the scroll view can be resized to shrink its overall window so that there is space for an input method.

How do I get the EditText above my keyboard?

After research I figured out that to work in some cases parent layout has to be set android:fitsSystemWindows="true" . Then native functionality of scrolling EditText above scrollbar working like a charm. Show activity on this post. Simply setting android:fitsSystemWindows="true" in the layout xml worked for me.


Video Answer


3 Answers

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

like image 108
JosephW Avatar answered Nov 14 '22 21:11

JosephW


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()
        }
    }
like image 20
Zakhar Rodionov Avatar answered Nov 14 '22 23:11

Zakhar Rodionov


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>
like image 34
isles1217 Avatar answered Nov 14 '22 21:11

isles1217