XTableView:一个带侧滑菜单的二维表格控件,kotlin 高阶函数源码讲解
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
mScrollHelper.notifyScroll(scrollDistance);
mScrollHelper.setScrollX(scrollDistance);
postInvalidate();
}
super.computeScroll();
}
将当前这个 LinearLayout 滚动的最新值去更新全局 scrollX 值,并且通知 ScrollHelper
触发其它 LinearLayout 同步滚动:
public class ScrollHelper {
...
public void notifyScroll(int x) {
for (int i = 0; i < itemViewsMap.size(); i++) {
itemViewsMap.get(itemViewsMap.keyAt(i)).notifyScroll(x);
}
}
...
}
当然,记得在 View 被销毁的时候清除集合数据,避免泄露。
[](
)如何实现惯性滚动?
主要借助于 Scroller
的 fling
方法,fling 可以让 View 在滑动到某个位置之后以一定的速度惯性滚到一段距离。因此在收到 MotionEvent.ACTION_UP
事件时(即手指抬起时),将惯性滚动前的初始 ScrollX 值作为 fling 的起始参数,然后依旧是在 computeScroll
方法里面获取最新滚动到的 ScrollX 值去同步给其他 LinearLayout,实现所有横向列表整体惯性。
[](
)如何处理侧滑与横向列表的滑动冲突?
这里的侧滑实现是基于 SwipeRecyclerView 这个库的基础上进行修改,所以这里自定义一个 RecyclerView
继承于 SwipeRecyclerView
重写其 onInterceptTouchEvent
方法,每次收到 MotionEvent.ACTION_MOVE
事件的时候,判断当前内容区是否滑到了最左侧界线,分别做如下处理:
如果此时位于最左侧界线,判断当前手势是左滑还是右滑,如果是右滑,那就通过 super.onInterceptTouchEvent(e)交由 SwipeRecyclerView 去处理侧滑逻辑,如果是左滑,则需要 return true 拦截事件,然后在 onTouchEvent 中做横向滚动处理。 如果当前不在左侧界线,说明无论左滑还是右滑,横向列表皆有滑动的空间,同样 return true 拦截事件交由 onTouchEvent 中做横向滚动处理。
[](
)如何使用
在项目根目录的 b
uild.gradle 添加:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
在项目的 build.gradle 添加如下依赖:
implementation 'com.github.GitHubZJY:XTableView:v1.0.0'
[](
)1.在 xml 中引用 XTableView
<com.zjy.xtableview.XTableView
android:id="@+id/table_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:swipeLayout="@layout/table_swipe_menu_layout"
app:headerHeight="50dp"
app:rowHeight="80dp"
app:cellWidth="130dp">
</com.zjy.xtableview.XTableView>
[](
)2.在代码中初始化 XTableView
ITableView vTableView = findViewById(R.id.table_view);
//设置是否支持长按拖动列表项
vTableView.setLongPressDragEnable(true);
//设置是否支持侧滑菜单
vTableView.setSwipeEnable(true);
[](
)3.绑定数据
绑定数据的设计灵感来自于 RecyclerView 的 adapter 设计,与数据相关的操作均通过 XTableAdapter
作为中间者来进行:
[](
)1.自定义一个 adapter 继承于 XTableAdapter
,通过实现 adapter 的方法,自定义表格样式。XTableAdapter
的各个方法作用如下:
onBindHeader 创建列头部视图 onCreateTableItem 创建每一个单元格的视图 onBindTableItem 绑定每一个单元格的视图数据 onCreateRowHeader 创建每一行的头部视图 onBindRowHeader 绑定每一行的头部视图数据
public class CustomTableAdapter extends XTableAdapter<String, TableRowModel<TableRowHeaderModel, TableRowCellModel>>{
public CustomTableAdapter(Context context) {
super(context);
}
@Override
public View onBindHeader(int position, String t) {
TextView cellTv = new TextView(getContext());
cellTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
cellTv.setGravity(Gravity.CENTER);
cellTv.setText(t);
return cellTv;
}
@Override
public View onCreateTableItem(int position) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.table_item_cell_layout, null);
TextView cellTv = view.findViewById(R.id.cell_tv);
cellTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
cellTv.setGravity(Gravity.CENTER);
return view;
}
@Override
public void onBindTableItem(int position, View view, TableRowModel<TableRowHeaderModel, TableRowCellModel> rowModel) {
final TableRowCellModel cellModel = rowModel.getRowData().get(position);
TextView cellTv = view.findViewById(R.id.cell_tv);
cellTv.setTextColor(cellModel.isRise() ?
getColor(R.color.table_view_rise_txt_color)
: getColor(R.color.table_view_fall_txt_color));
cellTv.setText(cellModel.getContent());
cellTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getContext(), cellModel.getContent(), Toast.LENGTH_SHORT).show();
}
});
}
@Override
public View onCreateRowHeader(int position) {
return LayoutInflater.from(getContext()).inflate(R.layout.table_item_title_layout, null);
}
@Override
public void onBindRowHeader(int position, View view, TableRowModel<TableRowHeaderModel, TableRowCellModel> rowModel) {
TextView vTitle = view.findViewById(R.id.title_tv);
TextView vDetail = view.findViewById(R.id.detail_tv);
String title = rowModel.rowHeader.getTitle();
String detail = rowModel.rowHeader.getDetail();
vTitle.setText(TextUtils.isEmpty(title) ? "" : title);
vDetail.setText(TextUtils.isEmpty(detail) ? "" : detail);
}
}
[](
)2.通过 adapter 的 bindData
绑定自定义数据源.
评论