如果你对RecyclerView原理还不是特别了解,非常建议你读一下。
本文的项目也是学习自定义LayoutManager绝佳资料,大家有需要的可以好好拜读。
前言
表格是自打我进公司以后就使用的控件,起初使用的是ScrollablePanel,从一开始的被花式吊打,到后期的熟练使用。
大佬写的控件确实给我的工作带来了极大的方便,不过还是有些问题存在:
- 无法实现不规则的表格
- 其核心是二层RecyclerView的嵌套,如果只用一层RecyclerView将会带来性能的提升
- 多个RecyclerView有的时候会导致界面变形
在我深入学习RecyclerView
以后,想能不能只用一层RecyclerView
,借助LayoutManager
实现,写着写着,发现该思路可行,并实现了一款基于一个RecyclerView
的表格控件TableView
,先看一下效果:
照片墙
经常看到有同学问类似的首页如何实现,现在不用自定义View也可以轻松实现了哈~
课程表
表格
TableView具有如下特点:
- 支持不规则表格
- 同时支持横向和纵向滚动
- 支持顶部和左侧悬浮
- 基于RecyclerView,所以RecyclerView自定义子视图、高效回收、子视图多样性这些特点它都有
- 没有多层RecyclerView嵌套,性能更棒
使用
第一步 | 添加xml文件
-
<?xml version="1.0" encoding="utf-8"?>
-
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-
xmlns:tools=
"http://schemas.android.com/tools"
-
android:layout_width=
"match_parent"
-
android:layout_height=
"match_parent"
-
tools:context=
".ui.fragment.table.TableFragment">
-
-
<com.orient.me.widget.rv.adapter.TableView
-
android:id=
"@+id/tb"
-
android:layout_width=
"match_parent"
-
android:layout_height=
"match_parent"/>
-
-
</FrameLayout>
第二步 | 获取TableView
在展示代码之前,了解一下TableView中的主要函数:
方法 | 描述 |
---|---|
setTitle(boolean isLeftOpen, boolean isTopOpen) |
左侧或者上侧的悬浮标题是否显示,默认显示 |
setModeAndValue(int mode, int w, int h) |
mode-表格模式、w-具体的宽度\一行容纳的单元格数、h-具体的高度\一列容纳的单元格数 |
这个setTitle(boolean isLeftOpen, boolean isTopOpen)
有什么作用呢?为了确保表格的每一个单元格的长度和宽度都一样(子视图可以在横纵方向上占有多个单元格),宽和高都使用两种方式:
- 设置具体的值,那么单元格的宽或者高的值就是具体的
- 设置一行或者一列可以容纳的单元格数量
所以宽高各有两种,模式的数量 = 2 * 2,总共有:
Mode模式 | w的说明 | h的说明 |
---|---|---|
TableLayoutManager.MODE_A |
父布局一行容纳的单元格数 | 父布局一列容纳的单元格数 |
TableLayoutManager.MODE_B |
单元格宽度 | 单元格高度 |
TableLayoutManager.MODE_C |
父布局一行容纳的单元格数 | 单元格高度 |
TableLayoutManager.MODE_D |
单元格宽度 | 父布局一列容纳的单元格数 |
代码:
-
//
if
use butterknife
-
//
or
use findViewById
-
@BindView(R.id.tb)
-
TableView mTable;
-
-
// 默认为 TableLayoutManager.MODE_A,
4,
8
-
mTable.setModeAndValue(TableLayoutManager.MODE_A,
6,
8);
第三步 | 创建数据类
实现ICellItem
接口:
-
public
class TableCell implements ICellItem {
-
-
private String name;
-
private String value;
-
private
int type;
-
private
int row;
-
private
int col;
-
private
int widthSpan;
-
private
int heightSpan;
-
-
//... 省略构造函数和Get Set方法
-
-
@Override
-
public int getRow() {
-
return row;
-
}
-
-
@Override
-
public int getCol() {
-
return col;
-
}
-
-
@Override
-
public int getWidthSpan() {
-
return widthSpan;
-
}
-
-
@Override
-
public int getHeightSpan() {
-
return heightSpan;
-
}
-
}
第四步 | 设置适配器
-
private TableAdapter<TableCell> mAdapter;
-
-
protected void initWidget(View root) {
-
// 假设在这个方法中初始化
-
mTable.setAdapter(mAdapter =
new TableAdapter<TableCell>(
new ArrayList<>()) {
-
@Override
-
public int getItemLayout(TableCell tableCell, int pos) {
-
// ... 返回子视图布局文件
-
// 支持多类型
-
return R.layout.table_cell_content_item;
-
}
-
-
@Override
-
public BaseAdapter.
ViewHolder<TableCell> onCreateViewHolder(View root, int itemType) {
-
// itemType是子视图布局文件
-
// 根据布局返回具体的ViewHolder
-
return
new ContentHolder(root);
-
}
-
});
-
}
-
-
// 具体的ViewHolder
-
class ContentHolder extends BaseAdapter.ViewHolder<TableCell>{
-
-
TextView mContent;
-
-
public ContentHolder(View itemView) {
-
super(itemView);
-
mContent = itemView.findViewById(R.id.tv_name);
-
}
-
-
@Override
-
protected void onBind(TableCell tableCell) {
-
mContent.setText(tableCell.getValue());
-
}
-
}
第五步 | 重新测绘
如果TableView
使用的模式是Mode_A
、Mode_C
和Mode_D
,需要再重新测量:
mTable.post(() -> mTable.reMeasure());
总结
总的来说,TableView
的核心是TableLayoutManager
,也就是RecyclerView
中的LayoutManager
,类似于可以随时横纵向切换的GridLayoutManager
,如果各位同学对TableView
感兴趣,我将会在后续的文章深入原理。
最后对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!
最后这里是关于我自己的Android 学习,面试文档,视频收集大整理,有兴趣的伙伴们可以看看~
转载:https://blog.csdn.net/weixin_44339238/article/details/104200894