当没有足够的项目来填充屏幕高度时,如何强制RecyclerView滚动

leo*_*dzn 6 android android-layout android-recyclerview

我在NavigationView中创建了一个RecyclerView,其自定义的第一项与ListView的addHeaderView()相当.在该标题布局的底部,我放置了一个EditText,以便我可以过滤掉下面的列表.

我想要做的是一直向上滚动RecyclerView,直到EditText成为最上面的项目,只要EditText获得焦点.但是,如果我的项目数量足够小以至于无法填充NavigationView的整个高度,则RecyclerView会拒绝一直向上滚动,从而显示除EditText之外的更多标题.作为一个附加问题,即使列表足够大,一旦我开始过滤列表项,它仍会向下滚动.

即使我没有足够的物品来填充视图的高度,我怎么能强制我的RecyclerView仍然一直向上滚动,以便我的标题的其余部分不会偷看?

这是我想要实现的目标的可视化:

 _______________
| HEADER LINE 1 |
| HEADER LINE 2 |
| HEADER LINE 3 |
| ------------- |
|  Search box   |
| ------------- |
| List item 1   |
| List item 2   |
| List item 3   |
 ---------------
Run Code Online (Sandbox Code Playgroud)

当我专注于搜索框时的预期行为:

 _______________
| ------------- |
|  Search box   | <- becomes the topmost item. I can already achieve this
| ------------- |    with RecyclerView.smoothScrollBy(dx, dy)
| List item 1   |    except when the list is small enough (see below)
| List item 2   |
| List item 3   |
| List item 4   |
|               | <- empty space is okay and is desired if dataset
|               |    is small enough
 ---------------
Run Code Online (Sandbox Code Playgroud)

实际发生了什么:

 _______________
| HEADER LINE 2 |  <- the header is 'bleeding' on top
| HEADER LINE 3 |
| ------------- |
|  Search box   |  <- search box cannot take the topmost spot
| ------------- |     as the recycler tries to position itself to fill in
| List item 1   |     the bottom part with items
| List item 2   |
| List item 3   |
| List item 4   |  <- items are pushed down to the bottom to fill
 ---------------      in the space
Run Code Online (Sandbox Code Playgroud)

这是我的NavigationView xml的片段(只是你的典型设置):

<android.support.design.widget.NavigationView
    android:id="@+id/navigation_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/drawer_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</android.support.design.widget.NavigationView>
Run Code Online (Sandbox Code Playgroud)

这里带有自定义标题的ViewHolder(RecyclerView Adapter):

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if(viewType == HEADER) {
        return new HeaderHolder(mHeaderView);
    } else {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_item, parent, false);

        return new ItemViewHolder(v);
    }
}
Run Code Online (Sandbox Code Playgroud)

抽屉标题只是我在主要活动中膨胀的xml布局(我在那里指定了监听器和动画)并通过我制作的setHeaderView(View标头)传递给我的RecyclerView适配器.

Dan*_*eDC 1

您需要的是与页眉高度相同的页脚。

这里有两种情况需要考虑:

  1. 您的标题有固定的高度
  2. 您的标题具有动态高度

对于第一种情况,解决方案非常简单。只需将页眉的高度定义为某个值<dimen name="header_height">300dp</dimen>,然后定义页眉和页脚,如下所示:

<FrameLayout
    android:layout_height="@dimen/header_height">

    <!-- Content goes here -->

</FrameLayout>
Run Code Online (Sandbox Code Playgroud)

在第二种情况下,我们必须做几件事:

  • 每当标题发生变化时检索标题的高度
  • 将页脚的高度更新为页眉高度的任意值

有很多方法可以做到这一点。我之前使用过的一种方法是,您可以ViewTreeObserver.OnPreDrawListener在 RecyclerView 上使用 a 来检测标头何时具有高度(以及随后是否已更改),然后将该高度传递给您,RecyclerView.Adapter它将使用它来设置请求的高度当页脚膨胀时,您只需使用notifyItemChanged(int)页脚索引调用适配器即可告诉它重新膨胀您的页脚。这是我刚刚在代码中描述的大部分内容:

final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.drawer_content);
recyclerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
    @Override
    public boolean onPreDraw() {
        if(recyclerView.getChildCount() < 1 || recyclerView.getChildAt(0) == null || recyclerView.getChildAt(0).getHeight() == 0) {
            return true;
        }

        int headerHeight = recyclerView.getChildAt(0).getHeight();
        adapter.setFooterHeight(headerHeight);

        return true;
    }
});
Run Code Online (Sandbox Code Playgroud)

在你的适配器中:

int footerHeight = 0;

public void setFooterHeight(int footerHeight){
    if(this.footerHeight == footerHeight){
        return;
    }

    this.footerHeight = footerHeight;
    notifyItemChanged(getItemCount() - 1);
}
Run Code Online (Sandbox Code Playgroud)

然后您唯一需要做的另一件事就是像您已经是页眉一样膨胀您的页脚并将其高度设置为footerHeight

希望这可以帮助。