使用 adjustpan 时 ActionBar 向上滚动

ActionBar is scrolled up when using adjustpan

我已经陷入这个问题很长一段时间了。我正在尝试开发一个聊天模块。当 SoftInputKeyboard 覆盖 RecyclerView 的内容时,我一直陷入这一部分。我几乎尝试了 adjustResizeadjustPanstateHiddenstateVisible 的所有组合,但都没有成功。

在使用 adjustPan 时,ActionBar 与 2-3 recyclerview 项一起被隐藏。 我附上了截图。任何帮助将不胜感激。

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>

当键盘为 shown/hidden 时,android:windowSoftInputMode 不会为您滚动内容。

文档说:

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.

基本上这意味着 adjustResize 使您的 rootview 变小并将 softKeyboard 放在它下面。 adjustPan 将根视图的上半部分推出屏幕,为软键盘腾出空间。

我建议使用 adjustResize,因为它不会将您的工具栏推出屏幕。然后你将不得不自己滚动内容。显然说起来容易做起来难,但是有一些内置的方法可以做到这一点。

首先,您必须获得 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();
        }
    });
    //...
}

然后你要做的就是在显示 SoftKeyboard 时滚动到该项目,问题是没有内置的方法来获取何时显示键盘,幸运的是有人已经在这里解决了这个问题:

使用 Jaap 的回答,我们可以添加如下内容:

//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);
    //...
}

最后不要忘记在 activity 被销毁时删除全局侦听器:

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

已接受的答案对我不起作用。 这有效:

在清单中的 activity 标签中,添加 android:windowSoftInputMode="adjustResize" .

在 activity 的 onCreate 方法中添加:

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);