1

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>
  • A ) AdjustResize

With AdjustResize

  • B ) With AdjustPan

enter image description here

M.Waqas Pervez
  • 2,440
  • 2
  • 19
  • 32
  • I do not see where the problem is. It is obvious that if you use adjustPan then all the activity, included ActionBar, must be moved up to show the View with the focus. If you do not want that to happen, use adjustResize – Lluis Felisart Mar 15 '17 at 12:39
  • I suggest you these things: 1. try to add your custom ActionBar if you want to show action bar 2. Try to add theme in your activity 3. Try to modify your xml layout that will help you. – parik dhakan Mar 16 '17 at 06:23
  • @parikdhakan can u explain the 2nd and 3rd point please ? – M.Waqas Pervez Mar 16 '17 at 07:22
  • 2. Try to add theme in your activity: It means you can use custom theme in your activity with no action bar and then you can use it. Add theme in your activity that is diff from main theme that you inlcude in main app theme. 3. Try to modify your xml layout that will help you : It means you need to change your xml layout design that you can include your custom action bar layout there. It complete your all need that you want. Hope it will help you – parik dhakan Mar 16 '17 at 09:35
  • Custom or not custom the ActionBar will be always pushed up with the containing Activity if adjustPan mode is used. Please explain why you don't want to use adjustResize mode. – Lluis Felisart Mar 16 '17 at 16:02
  • @Tonteria24 as u can see in the image. By using `AdjustResize` the keyboard overlays my recyclerview items. i want to push them up somehow. – M.Waqas Pervez Mar 16 '17 at 19:01
  • I disagree, adjustResize resizes the activity to fit the keyboard below, it does not overlap. – Lluis Felisart Mar 16 '17 at 20:54

2 Answers2

1

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);
}
Community
  • 1
  • 1
Nicolas Tyler
  • 9,372
  • 4
  • 38
  • 62
  • thank you for the solution and i works but now when i close the keyboard i cant scroll the recyclerview anymore. it is only scrollable if the keyboard is visible... – M.Waqas Pervez Mar 14 '17 at 13:30
  • It should scroll with and without the keyboard, I noticed that I left out where the `rootLayout` is created, I have added it in. – Nicolas Tyler Mar 15 '17 at 12:09
  • it is stuck in a callback when keyboard is opened it calls the `onGlobalLayout` which then call this line continuously `recyclerview_chat_main.getLayoutManager().scrollToPosition(lastVisiblePosition);`. cause of this it is always scrolled to the last position. – M.Waqas Pervez Mar 16 '17 at 09:47
  • 1
    got it to work after adding `scrollToPositionWithOffset(lastVisiblePosition,Offse)t` instead of `scrollToPosition(lastVisiblePosition)`. great answer. thank you – M.Waqas Pervez Mar 16 '17 at 19:02
  • To be honest I never tested this. It was more of a pseudo code thing. – Nicolas Tyler Mar 17 '17 at 08:36
1

The accepted answer didn't work for me. This works:

In your activity tag in manifest, add android:windowSoftInputMode="adjustResize".

In onCreate method of your activity add this:

View.OnLayoutChangeListener layoutChangeListener = new View.OnLayoutChangeListener()
{
    @Override
    public void onLayoutChange(View v, int left, final int top, int right, final int bottom,
                        int oldLeft, final int oldTop, int oldRight, final int oldBottom)
    {
        if (oldBottom != 0)
        {
            //when softkeyboard opens, the height of layout get's small, and when softkeyboa
            //-rd closes the height grows back(gets larger).We can find the change of height
            // by doing oldBotton - bottom, and the result of subtraction is how much we nee
            //-d to scroll. Change of height is positive if keyboard is opened, and negative
            //if it's closed.
            int pixelsToScrollVertically = oldBottom - bottom;
            recyclerView.scrollBy(0, pixelsToScrollVertically);
        }
    }
};


myAdapter = new MyAdapter();
recyclerView.setAdapter(myAdapter);

recyclerView.addOnLayoutChangeListener(layoutChangeListener);
Tayyab Mazhar
  • 662
  • 5
  • 11