前言:
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、代码中使用:
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不需要拖拽功能的忽略即可。
适配器:
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@Overridepublic 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")@Overridepublic 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();});}@Overridepublic int getItemCount() {return mList.size();}@Overridepublic 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;}@Overridepublic 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);}@Overridepublic 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;}@Overridepublic 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中使用:
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);