recyclerview android gridview android-recyclerview

android - LayoutManager para RecyclerView Grid con diferente ancho de celda



gridlayoutmanager (2)

StaggeredGridLayoutManager no parece permitir personalizar el ancho de una celda o abarcar varias columnas (excepto el tramo completo) para la orientación vertical.

¿Qué es un LayoutManager preferido para organizar celdas como se muestra arriba?

PS Solo quiero saber cómo personalizar el ancho de celda y no la altura con StaggeredGridLayoutManager . Sé que la altura se puede personalizar como se implementa en esta sample .

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

Adaptador

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) no afecta el ancho de la celda.

Para simplificar, actualizo mi diseño de cuadrícula a

¿Cómo aumentar el ancho de la celda 0 en comparación con la celda 1 en un StaggeredGridLayoutManager o cualquier otro administrador de diseño?


Para todos los demás, si busca una solución sin simplificar su diseño, puede consultar mi respuesta aquí o leer más.

Muchas gracias a Nick Butcher ! Su administrador de diseño llamado SpannableGridLayoutManager es capaz de hacer esto.

  1. Descargue SpannableGridLayoutManager desde aquí

    Por alguna razón tuve que cambiar esta línea:

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

    a

    while (lastVisiblePosition < lastItemPosition) {

    para que el gerente trabaje.

  2. Establezca SpannableGridLayoutManger en su RecyclerView

En tu caso:

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

Lo que le dará exactamente lo que está en la primera imagen de la pregunta.


Puede usar StaggeredGridLayoutManager.LayoutParams para cambiar el ancho y el alto de las celdas. Lo que espera diseñar sigue un patrón simple. Si asigna un índice a cada celda (en el orden en que StaggeredGridLayoutManager ordena por defecto) tendrá esto:

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

Primero declare algunas constantes en el adaptador para definir tipos de tramas:

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

Luego getItemViewType método getItemViewType en su adaptador de esta manera:

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

Todo lo que necesita hacer es cambiar layoutparams considerando viewType del 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; }

Mi adaptador siempre devuelve 50 para el recuento de elementos (solo una prueba) y utilicé un archivo de diseño simple, contiene un LinearLayout y un TextView para mostrar la posición del titular. Recuerde que debe pasar 2 para spanCount (en el constructor StaggeredGridLayoutManager ) debido a su diseño.

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

PD : para las personas perezosas como yo, tal vez sea una forma más sencilla en lugar de extender mi LayoutManager personalizado, pero estoy seguro de que hay mejores formas de lograrlo.

Actualización : la parte actualizada de su pregunta es más simple, puede usar 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);

De esta manera, configura 3 para el tamaño de intervalo predeterminado, luego, considerando la posición de su intervalo, cada elemento ocupa 1, 2 o 3 intervalos, algo como esto:

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