web-dev-qa-db-fra.com

LayoutManager pour RecyclerView Grid avec une largeur de cellule différente

StaggeredGridLayoutManager ne semble pas permettre de personnaliser une largeur de cellule ou de s'étendre sur plusieurs colonnes (sauf la pleine portée) pour une orientation verticale.

enter image description here

Quel est le LayoutManager préféré pour organiser les cellules comme indiqué ci-dessus?

PS Je veux juste savoir comment personnaliser la largeur des cellules et non la hauteur avec StaggeredGridLayoutManager. Je sais que la hauteur peut être personnalisée comme implémentée dans ce exemple .

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

Adaptateur

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) n'affecte pas la largeur des cellules.

Pour simplifier, je mets à jour ma disposition de grille en

enter image description here

Comment augmenter la largeur de la cellule 0 par rapport à la cellule 1 dans un StaggeredGridLayoutManager ou tout autre gestionnaire de disposition?

23
random

Vous pouvez utiliser StaggeredGridLayoutManager.LayoutParams pour modifier la largeur et la hauteur des cellules, ce que vous prévoyez de concevoir suit un modèle simple, si vous attribuez à chaque cellule un index (dans l'ordre que StaggeredGridLayoutManager les organise par défaut), vous obtiendrez ceci:

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

déclarez d'abord quelques constantes dans l'adaptateur pour définir les types d'étendue:

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

Remplacez ensuite la méthode getItemViewType dans votre adaptateur comme ceci:

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

Tout ce que vous devez faire est de modifier les paramètres de mise en page en tenant compte de viewType du 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;
}

Mon adaptateur renvoie toujours 50 pour le nombre d'articles (juste un test) et j'ai utilisé un fichier de mise en page simple pour les articles, il contient un LinearLayout et un TextView pour montrer la position du titulaire, rappelez-vous que vous devriez passez 2 pour spanCount (dans le constructeur StaggeredGridLayoutManager) à cause de votre conception.

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

}

enter image description here

[~ # ~] ps [~ # ~] : Pour les paresseux comme moi, c'est peut-être un moyen plus simple que d'étendre ma coutume LayoutManager, Mais je suis sûr qu'il existe de meilleures façons d'y parvenir.

Mise à jour : Une partie mise à jour de votre question est plus simple, vous pouvez utiliser 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 cette façon, vous définissez 3 pour la taille de travée par défaut, puis en considérant la position de votre travée, chaque élément occupe 1, 2 ou 3 travées, quelque chose comme ceci:

enter image description here

Item0.width == 2 X Item1.width
Item2.width == 3 X Item1.width
Item0.width == 2/3 X Item1.width
48
Farshad Tahmasbi

Pour tout le monde, à la recherche d'une solution sans simplifier votre mise en page, vous pouvez consulter ma réponse ici , ou vous pouvez en savoir plus.

Un grand merci à Nick Butcher ! Son gestionnaire de mise en page appelé SpannableGridLayoutManager est capable de le faire.

  1. Télécharger SpannableGridLayoutManager d'ici

    Pour une raison quelconque, j'ai dû changer cette ligne:

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

    à

    while (lastVisiblePosition < lastItemPosition) {
    

    pour faire travailler le manager.

  2. Définissez SpannableGridLayoutManger sur votre RecyclerView

Dans ton cas:

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

Ce qui vous donnera exactement ce qu'il y a dans la première image de la question.

enter image description here

7
kristyna