LayoutManager для сетки RecyclerView с различной шириной ячейки

StaggeredGridLayoutManager, похоже, не позволяет настраивать ширину ячейки ячейки или охватывать несколько столбцов (кроме полного диапазона) для вертикальной ориентации.

введите описание изображения здесь

Что является предпочтительным LayoutManager для организации ячеек, как показано выше?

P.S. Я просто хочу знать, как настроить ширину ячейки, а не высоту с помощью StaggeredGridLayoutManager. Я знаю, что высота может быть настроена как реализованная в этом образце.

public class VerticalStaggeredGridFragment extends RecyclerFragment {

    public static VerticalStaggeredGridFragment newInstance() {
        VerticalStaggeredGridFragment fragment = new VerticalStaggeredGridFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    protected RecyclerView.LayoutManager getLayoutManager() {
        return new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
    }

    @Override
    protected RecyclerView.ItemDecoration getItemDecoration() {
        return new InsetDecoration(getActivity());
    }

    @Override
    protected int getDefaultItemCount() {
        return 100;
    }

    @Override
    protected SimpleAdapter getAdapter() {
        return new SimpleStaggeredAdapter();
    }
}

Адаптер

public class SimpleStaggeredAdapter extends SimpleAdapter {
    @Override
    public void onBindViewHolder(VerticalItemHolder itemHolder, int position) {
        super.onBindViewHolder(itemHolder, position);

        final View itemView = itemHolder.itemView;
        if (position % 4 == 0) {
            int height = itemView.getContext().getResources()
                    .getDimensionPixelSize(R.dimen.card_staggered_height);
            itemView.setMinimumHeight(height);
        } else {
            itemView.setMinimumHeight(0);
        }
    }
}

itemView.setMinimumWidth(customWidth) не влияет на ширину ячейки.

Чтобы упростить, я обновляю макет сетки до

введите описание изображения здесь

Как увеличить ширину ячейки 0 по сравнению с ячейкой 1 в StaggeredGridLayoutManager или любом другом менеджере компоновки?

Ответы

Ответ 1

Вы можете использовать StaggeredGridLayoutManager.LayoutParams для изменения ширины и высоты ячеек. То, что вы ожидаете от проектирования, следует по простому шаблону. Если вы назначаете каждой ячейке индекс (в порядке, в котором StaggeredGridLayoutManager упорядочивает их по умолчанию), вы будете иметь это:

index % 4 == 3           --->  full span cell
index % 8 == 0, 5        --->  half span cell
index % 8 == 1, 2, 4, 6  ---> quarter span cell

сначала объявить некоторые константы в адаптере для определения типов span:

private static final int TYPE_FULL = 0;
private static final int TYPE_HALF = 1;
private static final int TYPE_QUARTER = 2;

Затем переопределите метод getItemViewType в вашем адаптере следующим образом:

@Override
public int getItemViewType(int position) {
    final int modeEight = position % 8;
    switch (modeEight) {
        case 0:
        case 5:
            return TYPE_HALF;
        case 1:
        case 2:
        case 4:
        case 6:
            return TYPE_QUARTER;
    }
    return TYPE_FULL;
}

Все, что вам нужно сделать, это изменить layoutparams с учетом viewType holder:

@Override
public MyHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
    final View itemView =
            LayoutInflater.from(mContext).inflate(R.layout.items, parent, false);
    itemView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            final int type = viewType;
            final ViewGroup.LayoutParams lp = itemView.getLayoutParams();
            if (lp instanceof StaggeredGridLayoutManager.LayoutParams) {
                StaggeredGridLayoutManager.LayoutParams sglp =
                        (StaggeredGridLayoutManager.LayoutParams) lp;
                switch (type) {
                    case TYPE_FULL:
                        sglp.setFullSpan(true);
                        break;
                    case TYPE_HALF:
                        sglp.setFullSpan(false);
                        sglp.width = itemView.getWidth() / 2;
                        break;
                    case TYPE_QUARTER:
                        sglp.setFullSpan(false);
                        sglp.width = itemView.getWidth() / 2;
                        sglp.height = itemView.getHeight() / 2;
                        break;
                }
                itemView.setLayoutParams(sglp);
                final StaggeredGridLayoutManager lm =
                        (StaggeredGridLayoutManager) ((RecyclerView) parent).getLayoutManager();
                lm.invalidateSpanAssignments();
            }
            itemView.getViewTreeObserver().removeOnPreDrawListener(this);
            return true;
        }
    });

    MyHolder holder = new MyHolder(itemView);
    return holder;
}

Мой адаптер всегда возвращает 50 для количества элементов (просто тест), и я использовал простой файл макета для элементов. Он содержит LinearLayout и TextView, чтобы показать позицию владельца. Помните, что вы должны передать 2 для spanCount (int the StaggeredGridLayoutManager конструктор) из-за вашей конструкции.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    RecyclerView rv = (RecyclerView) findViewById(R.id.rv);
    StaggeredGridLayoutManager lm =
            new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
    rv.setLayoutManager(lm);
    rv.setAdapter(new MyAdapter(this));

}

введите описание изображения здесь

PS: Для ленивых людей, подобных мне, может быть, это более простой способ, чем расширение моего пользовательского LayoutManager, но я уверен, что есть лучшие способы достичь этого.

Обновление: Обновленная часть вашего вопроса более проста, вы можете использовать GridLayoutManager:

    GridLayoutManager glm = new GridLayoutManager(this, 3);
    glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
        @Override
        public int getSpanSize(int position) {
            if (position % 3 == 2) {
                return 3;
            }
            switch (position % 4) {
                case 1:
                case 3:
                    return 1;
                case 0:
                case 2:
                    return 2;
                default:
                    //never gonna happen
                    return  -1 ;
            }
        }
    });
    rv.setLayoutManager(glm);

Таким образом вы устанавливаете 3 для размера диапазона по умолчанию, затем, учитывая положение своего диапазона, каждый элемент занимает 1, 2 или 3 пролета, что-то вроде этого:

введите описание изображения здесь

Item0.width == 2 X Item1.width
Item2.width == 3 X Item1.width
Item0.width == 2/3 X Item1.width

Ответ 2

Для всех остальных, ищущих решение без упрощения макета, вы можете посмотреть мой ответ здесь, или вы можете прочитать больше.

Большое спасибо Нику Бучеру ! Его менеджер по расположению под названием SpannableGridLayoutManager способен сделать это.

  1. Загрузите SpannableGridLayoutManager здесь

    По какой-то причине мне пришлось изменить эту строку:

    while (availableSpace > 0 && lastVisiblePosition < lastItemPosition) {
    

    в

    while (lastVisiblePosition < lastItemPosition) {
    

    чтобы менеджер работал.

  2. Установите SpannableGridLayoutManger для вашего RecyclerView

В твоем случае:

SpannedGridLayoutManager manager = new SpannedGridLayoutManager(
            new SpannedGridLayoutManager.GridSpanLookup() {
                @Override
                public SpannedGridLayoutManager.SpanInfo getSpanInfo(int position) {
                    switch (position % 8) {
                        case 0:
                        case 5:
                            return new SpannedGridLayoutManager.SpanInfo(2, 2);

                        case 3:
                        case 7:
                            return new SpannedGridLayoutManager.SpanInfo(3, 2);

                        default:
                            return new SpannedGridLayoutManager.SpanInfo(1, 1);
                    }
                }
            },
            3, // number of columns
            1f // default size of item
    );

Что даст вам именно то, что на первой картинке вопроса.

enter image description here

Ответ 3

Привет друзья, как спроектировать инстаграм модель поиска страницы в утилитаре