Android:RecyclerView跨行跨列的LayoutManager:Spannedgridlayoutmanager

前言:

RecyclerView可以使用GridLayoutManager实现跨行,但是不能跨列;瀑布流布局可以跨列但是又不能跨行。原生自带的各个LayoutManager中并没有可以又跨行又能跨列的。网上搜寻了一番,找到了一个亲测可行好用的三方库:spannedgridlayoutmanager。

实现效果预览:

依赖库的地址:

GitHub:GitHub - jmartinesp/SpannedGridLayoutManager: Android RecyclerView.LayoutManager that resizes and reorders views based on SpanSize

gitee:SpannedGridLayoutManager: Android RecyclerView.LayoutManager that resizes and reorders views based on SpanSize (gitee.com)

使用:

1、添加依赖:

复制代码
dependencies {
	implementation 'com.arasthel:spannedgridlayoutmanager:3.0.2'
}

如果依赖不成功或者想要自定义spannedgridlayoutmanager里面的代码,使用Module的方式来导入该项目。这边提供资源地址:spannedgridlayoutmanager-3.0.2资源-CSDN文库

2、代码中使用:

java 复制代码
        recyclerView.setAdapter(adapter);
        //参数Orientation.VERTICAL表示列表竖向;4表示4列
        SpannedGridLayoutManager gridLayoutManager = new SpannedGridLayoutManager(
                SpannedGridLayoutManager.Orientation.VERTICAL, 4);
        gridLayoutManager.setSpanSizeLookup(new SpannedGridLayoutManager.SpanSizeLookup(position -> {
            int col = 1;
            int row = 1;
            switch (adapter.getItemViewType(position)) {
                case ITEM_TYPE_1x2:
                    col = 2;
                    break;
                case ITEM_TYPE_1x4:
                    col = 4;
                    break;
                case ITEM_TYPE_2x1:
                    row = 2;
                    break;
                case ITEM_TYPE_2x2:
                    col = 2;
                    row = 2;
                    break;
                case ITEM_TYPE_1x1:
                default:
                    break;
            }
            return new SpanSize(col, row);
        }));
        recyclerView.setLayoutManager(gridLayoutManager);

根据你每一项item所需要占的格子数大小设置所跨宽和列的单元格个数。

就可以啦。

完整代码:

这边代码包含了item拖动功能,详细解释和实现方式可以参考我另一篇博客:Android:RecyclerView自由拖动itemhttp://t.csdnimg.cn/bPdbl不需要拖拽功能的忽略即可。

适配器:

java 复制代码
public class AppsCardAdapter extends RecyclerView.Adapter<AppsCardAdapter.MyHolder> {
    private final List<Integer> mList;
    private final Context mContext;

    private final int ITEM_TYPE_1x1 = 0;
    private final int ITEM_TYPE_1x2 = 1;
    private final int ITEM_TYPE_1x4 = 2;
    private final int ITEM_TYPE_2x2 = 3;
    private final int ITEM_TYPE_2x1 = 4;

    AppsCardAdapter(Context context) {
        this.mContext = context;
        mList = new ArrayList<>();
    }

    @NonNull
    @Override
    public MyHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int itemType) {
        View rootView = LayoutInflater.from(mContext).inflate(
                R.layout.item_apps_card, viewGroup, false);
        return new MyHolder(rootView);
    }

    @SuppressLint("SetTextI18n")
    @Override
    public void onBindViewHolder(@NonNull MyHolder holder, int position) {
        int item = mList.get(position);
        holder.name.setText(item + "");
        holder.itemView.setOnClickListener(view -> {
            Toast.makeText(mContext, "item = "+item, Toast.LENGTH_SHORT).show();
        });
    }

    @Override
    public int getItemCount() {
        return mList.size();
    }

    @Override
    public int getItemViewType(int position) {
         TODO: 根据实际项目item的类型来,这边为了演示直接定死位置的类型了 
        switch (mList.get(position)){
            case 0:
                return ITEM_TYPE_1x4;
            case 1:
            case 4:
            case 6:
                return ITEM_TYPE_1x2;
            case 2:
            case 3:
                return ITEM_TYPE_2x1;
            case 5:
                return ITEM_TYPE_2x2;
            default:
                return ITEM_TYPE_1x1;
        }
    }

    static class MyHolder extends RecyclerView.ViewHolder {
        TextView name;

        public MyHolder(@NonNull  View itemView) {
            super(itemView);
            name = itemView.findViewById(R.id.name);
        }
    }

    //拖动功能的回调类
    private static class MyItemTouchHelperCallback extends ItemTouchHelper.Callback{

        private final AppsCardAdapter appsCardAdapter;
        public MyItemTouchHelperCallback(AppsCardAdapter appsCardAdapter) {
            this.appsCardAdapter = appsCardAdapter;
        }

        @Override
        public int getMovementFlags(@NonNull  RecyclerView recyclerView,
                                    @NonNull  RecyclerView.ViewHolder viewHolder) {
            if (viewHolder.getItemViewType() == appsCardAdapter.ITEM_TYPE_1x4) {
                //不可拖动
                return makeMovementFlags(0, 0);
            }
            final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN
                    | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            return makeFlag(ItemTouchHelper.ACTION_STATE_DRAG, dragFlags);
        }

        @Override
        public boolean onMove(@NonNull  RecyclerView recyclerView,
                              @NonNull  RecyclerView.ViewHolder viewHolderSource,
                              @NonNull  RecyclerView.ViewHolder viewHolderTarget) {
            if (viewHolderTarget.getItemViewType() == appsCardAdapter.ITEM_TYPE_1x4) {
                //不可拖动到这里
                return false;
            }
            appsCardAdapter.onMove(viewHolderSource.getAdapterPosition(),
                    viewHolderTarget.getAdapterPosition());
            return true;
        }

        @Override
        public void onSwiped(@NonNull  RecyclerView.ViewHolder viewHolder, int i) {

        }
    }

    private void onMove(int sourcePosition, int targetPosition) {
        int item = mList.get(sourcePosition);
        mList.remove(sourcePosition);
        mList.add(targetPosition, item);
        notifyItemMoved(sourcePosition, targetPosition);
    }

    public void setRecyclerView(RecyclerView recyclerView) {
        recyclerView.setAdapter(this);
        SpannedGridLayoutManager gridLayoutManager = new SpannedGridLayoutManager(
                SpannedGridLayoutManager.Orientation.VERTICAL, 4);
        gridLayoutManager.setSpanSizeLookup(new SpannedGridLayoutManager.SpanSizeLookup(position -> {
            int col = 1;
            int row = 1;
            switch (getItemViewType(position)) {
                case ITEM_TYPE_1x2:
                    col = 2;
                    break;
                case ITEM_TYPE_1x4:
                    col = 4;
                    break;
                case ITEM_TYPE_2x1:
                    row = 2;
                    break;
                case ITEM_TYPE_2x2:
                    col = 2;
                    row = 2;
                    break;
                case ITEM_TYPE_1x1:
                default:
                    break;
            }
            return new SpanSize(col, row);
        }));
        recyclerView.setLayoutManager(gridLayoutManager);
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(
                new MyItemTouchHelperCallback(this));
        itemTouchHelper.attachToRecyclerView(recyclerView);
    }

    public void setNewData(List<Integer> list) {
        this.mList.clear();
        this.mList.addAll(list);
        notifyDataSetChanged();
    }
}

Activity中使用:

java 复制代码
        AppsCardAdapter adapter = new AppsCardAdapter(getContext());
        adapter.setRecyclerView(recyclerView);
        //测试数据
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 0; i < 13; i++) {
            list.add(i);
        }
        adapter.setNewData(list);

完。

相关推荐
fatiaozhang95271 小时前
中兴云电脑W102D_晶晨S905X2_2+16G_mt7661无线_安卓9.0_线刷固件包
android·adb·电视盒子·魔百盒刷机·魔百盒固件
CYRUS_STUDIO2 小时前
Android APP 热修复原理
android·app·hotfix
鸿蒙布道师2 小时前
鸿蒙NEXT开发通知工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
鸿蒙布道师2 小时前
鸿蒙NEXT开发网络相关工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
大耳猫3 小时前
【解决】Android Gradle Sync 报错 Could not read workspace metadata
android·gradle·android studio
ta叫我小白3 小时前
实现 Android 图片信息获取和 EXIF 坐标解析
android·exif·经纬度
dpxiaolong4 小时前
RK3588平台用v4l工具调试USB摄像头实践(亮度,饱和度,对比度,色相等)
android·windows
tangweiguo030519875 小时前
Android 混合开发实战:统一 View 与 Compose 的浅色/深色主题方案
android
老狼孩111225 小时前
2025新版懒人精灵零基础及各板块核心系统视频教程-全分辨率免ROOT自动化开发
android·机器人·自动化·lua·脚本开发·懒人精灵·免root开发
打死不学Java代码6 小时前
PaginationInnerInterceptor使用(Mybatis-plus分页)
android·java·mybatis