具有不同单元格宽度的 RecyclerView Grid 的 LayoutManager [英] LayoutManager for RecyclerView Grid with different cell width

查看:24
本文介绍了具有不同单元格宽度的 RecyclerView Grid 的 LayoutManager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

StaggeredGridLayoutManager 似乎不允许自定义单元格宽度或跨多个列(全跨度除外)垂直方向.

如上所示,用于组织单元格的首选 LayoutManager 是什么?

P.S. 我只想知道如何使用 StaggeredGridLayoutManager 自定义单元格宽度 而不是高度.我知道可以自定义高度,如在这个

StaggeredGridLayoutManager 或任何其他布局管理器中的单元格 1 相比,如何增加单元格 0 的宽度?

解决方案

你可以使用 StaggeredGridLayoutManager.LayoutParams 来改变单元格的宽度和高度,你期望设计的遵循一个简单的模式,如果你为每个单元格分配一个索引(按照 StaggeredGridLayoutManager 默认排列它们的顺序),您将拥有:

index % 4 == 3 --->全跨度单元格指数 % 8 == 0, 5 --->半跨单元索引 % 8 == 1, 2, 4, 6 --->四分之一跨度单元

首先在adapter中声明一些常量来定义span类型:

private static final int TYPE_FULL = 0;私有静态最终 int TYPE_HALF = 1;私有静态最终 int TYPE_QUARTER = 2;

然后像这样覆盖适配器中的 getItemViewType 方法:

@Override公共 int getItemViewType(int position) {最终 int modeEight = 位置 % 8;开关(模式八){案例0:案例5:返回 TYPE_HALF;情况1:案例2:案例4:案例6:返回类型_季度;}返回 TYPE_FULL;}

您需要做的就是考虑holderviewType来更改layoutparams:

@Overridepublic MyHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {最终视图 itemView =LayoutInflater.from(mContext).inflate(R.layout.items, parent, false);itemView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {@覆盖公共布尔 onPreDraw() {最终 int 类型 = 视图类型;最终 ViewGroup.LayoutParams lp = itemView.getLayoutParams();if (lp instanceof StaggeredGridLayoutManager.LayoutParams) {StaggeredGridLayoutManager.LayoutParams sglp =(StaggeredGridLayoutManager.LayoutParams) lp;开关(类型){案例 TYPE_FULL:sglp.setFullSpan(true);休息;案例 TYPE_HALF:sglp.setFullSpan(false);sglp.width = itemView.getWidth()/2;休息;案例类型_季度:sglp.setFullSpan(false);sglp.width = itemView.getWidth()/2;sglp.height = itemView.getHeight()/2;休息;}itemView.setLayoutParams(sglp);最终 StaggeredGridLayoutManager lm =(StaggeredGridLayoutManager) ((RecyclerView) parent).getLayoutManager();lm.invalidateSpanAssignments();}itemView.getViewTreeObserver().removeOnPreDrawListener(this);返回真;}});MyHolder holder = new MyHolder(itemView);退货持有人;}

我的适配器总是为项目计数返回 50(只是一个测试),我使用了一个简单的项目布局文件,它包含一个 LinearLayout 和一个 TextView 来显示持有人的位置,请记住,由于您的设计,您应该为 spanCount (在 StaggeredGridLayoutManager 构造函数中)传递 2.

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

附注:对于像我这样的懒人来说,这可能比扩展我的自定义 LayoutManager 更简单,但我相信有更好的方法来实现这一点.

更新:您问题的更新部分更简单,您可以使用 GridLayoutManager:

 GridLayoutManager glm = new GridLayoutManager(this, 3);glm.setSpanSizeLookup(新的GridLayoutManager.SpanSizeLookup(){@覆盖公共 int getSpanSize(int position) {如果(位置 % 3 == 2){返回3;}开关(位置 % 4){情况1:案例3:返回 1;案例0:案例2:返回2;默认://永远不会发生返回 -1 ;}}});rv.setLayoutManager(glm);

这样你把默认跨度大小设置为3,然后考虑你跨度的位置,每个项目占据1、2或3个跨度,像这样:

Item0.width == 2 X Item1.widthItem2.width == 3 X Item1.widthItem0.width == 2/3 X Item1.width

StaggeredGridLayoutManager doesn't seem to allow customising a cell width or span multiple columns (except full span) for vertical orientation.

What is a preferred LayoutManager for organising cells as shown above?

P.S. I just want to know how to customise cell width and not height with StaggeredGridLayoutManager. I know height can be customised as implemented in this 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();
    }
}

Adapter

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) doesn't affect cell width.

To simplify, I update my grid layout to

How to increase cell 0 width as compared to cell 1 in a StaggeredGridLayoutManager or any other layout manager?

解决方案

You can use StaggeredGridLayoutManager.LayoutParams to change width and height of cells, What you expect to design follows a simple pattern, If you assign every cell an index (in the order that StaggeredGridLayoutManager arranges them by default) you will have this:

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

first declare some constants in adapter to define span types:

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

Then override getItemViewType method in your adapter like this:

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

All you need to do is change layoutparams considering viewType of the 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;
}

My adapter always returns 50 for items count(just a test) and I used a simple layout file for items, It contains a LinearLayout and a TextView to show the position of holder, Remember you should pass 2 for spanCount (int the StaggeredGridLayoutManager constructor) because of your design.

@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: For lazy people like me maybe it's a simpler way rather than extending my custom LayoutManager, But I'm sure there are better ways to achieve this.

Update: Updated part of your question is more simpler, You can use 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);

In this way you set 3 for default span size, Then considering the position of your span, Each item occupies 1, 2 or 3 spans, Something like this:

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

这篇关于具有不同单元格宽度的 RecyclerView Grid 的 LayoutManager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆