当没有足够的项目填满屏幕高度时,如何强制RecyclerView滚动 [英] How to force RecyclerView to scroll when there's not enough items to fill the height of the screen

查看:918
本文介绍了当没有足够的项目填满屏幕高度时,如何强制RecyclerView滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在NavigationView中制作了一个RecyclerView,并带有一个自定义的第一项,等效于ListView的 addHeaderView().在该标题布局的底部,放置了一个EditText,以便可以过滤出下面的列表.

I made a RecyclerView inside a NavigationView with a custom first item as an equivalent to ListView's addHeaderView(). On the bottom part of that header layout I placed an EditText so that I can filter out the list below.

我想做的就是一直滚动RecyclerView直到每当EditText获得焦点时EditText就会成为最顶层的项目.但是,如果我的项目数足够小,以致于无法填满NavigationView的整个高度,则RecyclerView拒绝一直向上滚动,因此会显示除EditText之外的更多标题.另外一个问题是,即使列表足够大,一旦我开始过滤列表项,它仍然会向下滚动.

What I wanted to do was to scroll the RecyclerView all the way up until the EditText would be the topmost item whenever the EditText gains focus. However if my item count is small enough that it wouldn't be able to fill-up the entire height of the NavigationView, the RecyclerView refuses to scroll all the way up and thus showing a bit more of the header other than the EditText. As an added problem, even if the list is large enough, it stills scrolls back down once I start filtering the list items.

即使我没有足够的项目来填充视图的高度,如何使RecyclerView仍然一直向上滚动,以使其余标头不显示?

How can I force my RecyclerView to still scroll all the way up even if I don't have enough items in to fill the height of my view so that the rest of my header do not take a peek?

以下是我要实现的目标的可视化视图:

Here's a visualization of what I'm trying to achieve:

 _______________
| HEADER LINE 1 |
| HEADER LINE 2 |
| HEADER LINE 3 |
| ------------- |
|  Search box   |
| ------------- |
| List item 1   |
| List item 2   |
| List item 3   |
 ---------------

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

Expected behavior when I focus on the search box:

 _______________
| ------------- |
|  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
 ---------------

实际发生的事情:

 _______________
| 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

这是我的NavigationView xml的摘录(仅是您的典型设置):

Here's a snippet of my NavigationView xml (just your typical setup):

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

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

ViewHolder with custom header here (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);
    }
}

抽屉标头只是我在主要活动中夸张的xml布局(我在那里分配了侦听器和动画),并通过我制作的 setHeaderView(View header)传递给了我的RecyclerView适配器.

The drawer header is just an xml layout I inflated in the main activity (I assigned listeners and animations there) and passed on to my RecyclerView adapter via a setHeaderView(View header) I made.

推荐答案

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

这里有两种情况可供考虑:

There are two scenarios to consider here:

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

在第一种情况下,解决方案非常简单.只需使用某些值(如<dimen name="header_height">300dp</dimen>)定义页眉的高度,然后按如下所示定义页眉和页脚:

In the first case, the solution is very simple. Just define the height of your header in some value like <dimen name="header_height">300dp</dimen> and then define your header and footer like the following:

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

    <!-- Content goes here -->

</FrameLayout>

在第二种情况下,我们将不得不做两件事:

In the second case, we're going to have to do a couple of things:

  • 在标题更改时检索标题的高度
  • 将页脚的高度更新为页眉高度的任何值

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

There are lots of ways to do this. One such way that I have used before is that you could use a ViewTreeObserver.OnPreDrawListener on the RecyclerView to detect when the header has a height (and subsequently if it has changed) and then pass that height to your RecyclerView.Adapter which will use it to set the requested height for your footer when it inflates it, and then you just need to call notifyItemChanged(int) on the adapter with your footer's index to tell it to re-inflate your footer. Here's most of what I just described in code:

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

在您的适配器中:

int footerHeight = 0;

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

    this.footerHeight = footerHeight;
    notifyItemChanged(getItemCount() - 1);
}

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

And then the only other thing you'd need to do is inflate your footer like you are your header already and set its height to footerHeight.

希望这会有所帮助.

这篇关于当没有足够的项目填满屏幕高度时,如何强制RecyclerView滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆