Лучший способ реализовать заголовок поверх RecyclerView с использованием макета сетки?

Я пытаюсь реализовать изображение ниже. Моя первая мысль заключалась в том, чтобы все, что было выше планировки сетки, было первой строкой сетки и использовало SpanSizeLookup, чтобы установить размер диапазона в число столбцов в RecyclerView, но это похоже на то, что даст мне много проблем.

Я читал о размещении RecyclerView внутри NestedScrollView, люди говорят, что это работает, но я не могу заставить его работать правильно. Прокрутка, похоже, не работает правильно, я не могу заставить сетку даже отображаться без установки minHeight, но тогда это выглядит просто плохо.

Есть ли другой вариант, который я не рассматриваю, или это одно из направлений, в котором я должен идти?

Вот что я пытаюсь достичь

Ответ 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);
    }
}

Примерный вид заголовка может быть таким (вы бы назвали bindTo() из MyHeaderViewHolder).

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

Ответ 2

  • использовать StaggeredGridLayoutManager
  • используйте другой макет для вашего первого элемента (весь комплексный вид).
  • получить его параметры макета и setFullSpan

Это делает объект таким же широким, как сам RecyclerView (аналогично match_parent).

Установите различные клики для прослушивания в определенном ViewHolder, который отвечает за этот элемент. Используя этот подход, весь комплексный вид будет вести себя (прокручивать) как часть RecyclerView, все еще делая его доступным для (ввода) событий.

Ответ 3

  • Вы можете посмотреть Bookends

  • Или другой (как обычно я это делаю) способ использовать GridLayouManager с SpanSizeLookUp. И используйте несколько ViewTypes, то есть один для заголовка, нижнего колонтитула и элементов.

Перейдите на 1, если у вас есть только один заголовок и какой интерфейс ListView-ish в вашем коде.

Перейдите на 2, если вы не уверены в том, сколько пользовательских типов ViewTypes вы бы добавляли. Это гарантирует максимальную масштабируемость в будущем.

Если вы рассматриваете массивную масштабируемость, я предлагаю вам прочитать эту статью Ханнеса Дорфмана.