【问题标题】:Best way to implement header over a RecyclerView using a grid layout?使用网格布局在 RecyclerView 上实现标头的最佳方法?
【发布时间】:2015-11-07 06:18:31
【问题描述】:

我正在尝试实现下图。我的第一个想法是让网格布局上方的所有内容成为网格的第一行,并使用 SpanSizeLookup 将跨度大小设置为 RecyclerView 中的列数,但这感觉就像会给我带来很多问题。

我一直在阅读有关将 RecyclerView 放入 NestedScrollView 的文章,人们说它可以工作,但我似乎无法让它正常工作。滚动似乎无法正常工作,如果不设置 minHeight,我什至无法显示网格,但它看起来很糟糕。

是否有其他选择我没有考虑,或者其中一个是我应该采取的方向?

【问题讨论】:

  • 为什么需要嵌套滚动视图?是给 FAB 的吗?
  • 因为我不希望只有网格滚动,我希望整个滚动。如果网格只是线性布局下方的回收视图,那么线性布局将始终显示在屏幕上,而您只是在底部滚动一个小网格。我希望它的工作方式类似于 Instagram 的工作方式。
  • 然后让线性布局成为网格视图的一部分?如果您确定不会有太多页眉/页脚,您应该检查书挡。
  • 这是我正在考虑的选项之一,但它会将通常相当简单的代码分散到多个文件中。只是感觉有点矫枉过正。
  • 您对 RecyclerView 感觉如何。如果您喜欢,那么Jimeux's answer 是最好的方法。您将只有 2 个文件,(包括 bookend 库在内的 3 个文件)。我认为这样一个界面的文件数量相当多。

标签: android android-recyclerview


【解决方案1】:

您预计 SpanSizeLookup 会出现什么样的问题?您可以使用以下几行代码来实现它(我建议使用 integers.xml 中的值以获得灵活性)。

GridLayoutManager glm = new GridLayoutManager(getContext(), 3);
glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
    @Override public int getSpanSize(int position) {
        return (position == 0) ? 3 : 1;
    }
});

如果您的标题布局需要常规布局所没有的视图和字段,您将需要创建单独的视图并将它们告诉您的适配器。像这样的。

@Override
public int getItemViewType(int position) {
    if (position == 0)
        return TYPE_HEADER;
    else
        return TYPE_REGULAR;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == TYPE_HEADER) {
        MyHeaderView view = (MyHeaderView) LayoutInflater
                .from(parent.getContext())
                .inflate(R.layout.my_header_view, parent, false);
        return new MyHeaderViewHolder(view);
    } else {
        MyRegularView view = (MyRegularView) LayoutInflater
                .from(parent.getContext())
                .inflate(R.layout.my_regular_view, parent, false);
        return new MyRegularViewHolder(view);
    }
}

一个示例标题视图可能是这样的(您可以从MyHeaderViewHolder 调用bindTo())。

public final class MyHeaderView extends LinearLayout {
    @Bind(R.id.image) ImageView imageView;
    @Bind(R.id.title) TextView titleView;

    public MyHeaderView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        ButterKnife.bind(this);
    }

    public void bindTo(String imageUrl, String title) {
        Glide.with(getContext())
                .load(imageUrl).into(imageView);
        titleView.setText(title);
    }
}

【讨论】:

  • 是否可以在不更改适配器的情况下添加标题?也许使用 NestedScrollView?
  • 这就是我最终要做的,并没有真正遇到任何问题。
  • 我在一些应用程序中使用了这种方法,到目前为止效果很好。我想我从u2020 app 得到了大致的想法。不过,我同意你最初的担忧。在不同的文件中有这么多代码感觉有些不对劲,这让测试变得更加困难。
  • 这是我最初使用的解决方案,但我在拖放功能方面遇到了问题。在两种不同的项目视图类型之间拖动时,Android 会立即放下被拖动的项目。有解决办法吗?
【解决方案2】:

这使得项目与 RecyclerView 本身一样宽(类似于 match_parent)。

在负责此项的特定 ViewHolder 中设置各种点击侦听器。使用这种方法会将整个复杂视图设置为(滚动)作为 RecyclerView 的一部分,同时仍使其可用于(输入)事件。

【讨论】:

  • 谢谢我的朋友...我已经找了好几天了。
【解决方案3】:
  1. 你可以看看Bookends

  2. 或者另一种(我通常这样做的方式)方法是使用带有SpanSizeLookUp 的 GridLayouManager。并使用多种视图类型,即页眉、页脚和项目中的一种。

如果您只有一个标头并且代码中有一个 ListView-ish 接口,请选择 1。

如果您不确定要添加多少个自定义 ViewType,请选择 2。它可确保您在未来拥有最大的可扩展性。

如果您正在考虑大规模的可扩展性,我建议您阅读 Hannes Dorfman 的 this article

【讨论】:

    猜你喜欢
    • 2017-01-14
    • 1970-01-01
    • 1970-01-01
    • 2019-08-01
    • 2020-05-27
    • 1970-01-01
    • 1970-01-01
    • 2015-07-16
    • 2015-04-11
    相关资源
    最近更新 更多