androidandroid-actionbarandroid-recyclerviewwindow-soft-input-modeadjustpan

ActionBar is scrolled up when using adjustpan


I have been stuck into this for quite some time. I am trying to develop a chat module. I have been stuck into this part where when the SoftInputKeyboard overlays the content of the RecyclerView. I have tried almost every combination of adjustResize and adjustPan with stateHidden and stateVisible with no success at all.

On Using adjustPan the ActionBar gets hidden along with 2-3 recyclerview items. I have attached screenshots. Any help with be appreciated.

XML

  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/light_grey"
android:fitsSystemWindows="true"
android:focusable="true"
android:focusableInTouchMode="true">

<LinearLayout
    android:id="@+id/listFooter"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_marginTop="8dp"
    android:orientation="horizontal">

    <EditText
        android:id="@+id/messageInput"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@android:color/white"
        android:hint="Write a message"
        android:inputType="textMultiLine"
        android:padding="16dp"
        android:textSize="14sp" />

    <ImageView
        android:id="@+id/sendButton"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="@color/colorPrimary"
        android:contentDescription="@null"
        android:padding="12dp"
        android:src="@drawable/ic_send" />
</LinearLayout>

<android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerview_chat_main"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_above="@+id/listFooter"
    android:layout_marginTop="8dp" />
</RelativeLayout>

With AdjustResize

enter image description here


Solution

  • The android:windowSoftInputMode does not scroll your content for you when the keyboard is shown/hidden.

    The documentation says:

    adjustResize - The activity's main window is always resized to make room for the soft keyboard on screen.

    adjustPan - The activity's main window is not resized to make room for the soft keyboard. Rather, the contents of the window are automatically panned so that the current focus is never obscured by the keyboard and users can always see what they are typing. This is generally less desirable than resizing, because the user may need to close the soft keyboard to get at and interact with obscured parts of the window.

    Basically this means that adjustResize makes your rootview smaller and puts the softKeyboard below it. And adjustPan pushes the top half of the rootview out of the screen to make room for the the softKeyboard.

    I would suggest using adjustResize because it wont push your Toolbar out of the screen. Then you would have to scroll the content yourself. Its easier said than done obviously, but there are methods built in to do this.

    First you would have to get the last visible item position in the recyclerview.

    //class variable
    private int lastVisiblePosition = 0;
    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        //...
        recyclerview_chat_main.addOnScrollListener(new RecyclerView.OnScrollListener()
        {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy)
            {
                super.onScrolled(recyclerView, dx, dy);
                lastVisiblePosition = ((LinearLayoutManager)recyclerView.getLayoutManager()).findLastVisibleItemPosition();
            }
        });
        //...
    }
    

    Then you have to do is scroll to that item when the SoftKeyboard is shown, the issue with that is there is no built in way to get when the keyboard is shown, fortunately someone has already addressed that here: https://stackoverflow.com/a/25681196/2027232

    using Jaap's answer we could add something like this:

    //class variables
    private ViewGroup rootLayout = null;
    private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = null;
    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        //...
        ViewGroup rootLayout = (ViewGroup)findViewById(android.R.id.content);
        keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener()
        {
            @Override
            public void onGlobalLayout()
            {
                int heightDiff = rootLayout.getRootView().getHeight() - rootLayout.getHeight();
                int contentViewTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getHeight();
    
                if(heightDiff > contentViewTop)
                {
                    recyclerview_chat_main.getLayoutManager().scrollToPosition(lastVisiblePosition);
                }
            }
        };
        rootLayout.getViewTreeObserver().addOnGlobalLayoutListener(keyboardLayoutListener);
        //...
    }
    

    And lastly dont forget to remove the global listener when the activity gets destroyed:

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        if(rootLayout != null && keyboardLayoutListener != null)
            rootLayout.getViewTreeObserver().removeOnGlobalLayoutListener(keyboardLayoutListener);
    }