本篇给TableView添加几个事件处理,简单来说分为两种:整行(item)响应事件和单元格响应事件(两者互斥),考虑不响应任何事件的话就是三种,如下:
- 不响应事件(默认)
- item响应事件:点击、长按
- 单元格响应事件:点击、点击+选中
其他情况(比如item可以响应事件同时某一列单元格也可以响应事件)有需要的话可以根据本篇的思路自行扩展。
明确需求(上面列出的3点)之后,再理一下整体的实现思路,第1点什么都不用做,第2点很简单,注册ListView的item点击和长按事件即可,第3点也很简单,就是item里面的每个view注册点击事件(都是原生view自带的事件)。
1.首先根据3点需求定义3种模式
public static final int MODE_NONE_EVENT = 0; //不处理任何事件
public static final int MODE_ITEM_EVENT = 1; //item处理事件
public static final int MODE_ALL_UNIT_EVENT = 2; //所有单元格处理事件
public static final int MODE_EITHER_UNIT_EVENT = 3; //某列单元格处理事件
// 上面的 MODE_ALL_UNIT_EVENT 和 MODE_EITHER_UNIT_EVENT 算一种
2.定义一个变量表示当前事件模式
private int mEventMode;
3.在适当的地方判断当前模式,注册相应的事件
// item处理事件
if (mEventMode == MODE_ITEM_EVENT) {
mContentListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// item点击事件
}
});
mContentListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
//item长按事件
return true;
}
});
}
//单元格处理事件,在getView里面
if (mEventMode == MODE_ALL_UNIT_EVENT || mEventMode == MODE_EITHER_UNIT_EVENT) {
Point coordinate = new Point(i, position); //column=x, row=y
childView.setTag(coordinate); //记录单元格坐标
childView.setOnTouchListener(touchListener); //这里使用OnTouch实现点击,不用OnClick
}
3.1 解释一下上面单元格处理事件的一些东西
(1)使用OnTouch而不使用OnClick是因为方便设置单元格点击时按下状态的颜色变化
(2)注册事件是在Adapter的getView方法里面,所以不要使用局部匿名类的方式注册,避免频繁创建对象,上面代码参数touchListener是在getView方法之外定义的成员匿名类,代码如下
private View.OnTouchListener touchListener = new OnTouchListener() {
private boolean isContainsUnit = false;
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mIsUnitSelectable) {
Point coordinate = (Point) v.getTag(); //获取单元格坐标
isContainsUnit = mUnitSelectedMap.containsKey(coordinate);
int color = isContainsUnit ? mUnitBackColor : mUnitSelectedColor;
v.setBackgroundColor(color);
} else {
v.setBackgroundColor(mUnitDownColor);
}
} else if (event.getAction() == MotionEvent.ACTION_UP) { // UP的时候处理点击事件
Point coordinate = (Point) v.getTag();
if (mUnitClickListener != null) {
mUnitClickListener.onUnitClick(coordinate.y, coordinate.x, getRowData(coordinate.y)[coordinate.x]);
}
if (mIsUnitSelectable) {
if (isContainsUnit) {
mUnitSelectedMap.remove(coordinate);
} else {
mUnitSelectedMap.put(coordinate, getRowData(coordinate.y)[coordinate.x]);
}
} else {
v.setBackgroundColor(mUnitBackColor);
}
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
if (mIsUnitSelectable) {
int color = isContainsUnit ? mUnitSelectedColor : mUnitBackColor;
v.setBackgroundColor(color);
} else {
v.setBackgroundColor(mUnitBackColor);
}
}
return true;
}
};
touchListener里面实现了点击和选中的逻辑。
(3)因为不使用局部匿名类的方式注册,所以touchListener里面不能直接取得单元格view的行列坐标,这里利用了view的Tag实现坐标的记录与获取
4.实现自己的回调
上面3注册回调事件之后已经可以响应相应的事件了,但是原生的回调并不能完美满足需求。看图
上图说明了为什么要定义一个自己的回调,同时也展示了TableView最终对外提供注册单元格点击事件的方法的使用。
4.1 如何实现自己的回调(掌握回调的就不用看了,实现上图的效果就行)
// 1.首先定义一个回调接口
public interface OnUnitClickListener {
void onUnitClick(int row, int column, String unitText);
}
// 2.然后定义一个接口对象
private OnUnitClickListener mUnitClickListener;
// 3.在适当的地方调用接口里面的函数,并把相应的参数传进去(适当的地方在 3.1 的代码里)
mUnitClickListener.onUnitClick(row, column, unitText);
// 4.对外提供一个注册回调的方法
public void setOnUnitClickListener(OnUnitClickListener listener) {
mUnitClickListener = listener;
}
// 5.像4的代码截图里面那样使用
5.补充
在注册回调的时候需要设置相应的事件模式,以下选其一
tv.setEventMode(TableView.MODE_NONE_EVENT);//不处理任何事件(默认)
tv.setEventMode(TableView.MODE_ITEM_EVENT);//item处理点击和长按事件
tv.setEventMode(TableView.MODE_ALL_UNIT_EVENT);//所有单元格处理事件
tv.setEventMode(TableView.MODE_EITHER_UNIT_EVENT);//某些列的单元格处理事件
tv.setColumnEventIndex(1,7,9,18);//设置哪些列的单元格处理事件
其它相关
tv.setUnitSelectable(true);//单元格处理事件的时候是否可以选中
tv.setUnitDownColor(R.color.blue_color);//单元格处理事件的时候,按下态的颜色
tv.setUnitSelectedColor(R.color.cyan_color);//单元格被选中的颜色
Map<Point,String> selectedData = tv.getSelectedUnits();//获取所有选中的单元格数据
tv.clearSelectedUnits();//清除所有选中的单元格
tv.setUnitSelected(1,2);//在单元格可以被选中的时候,通过代码设置第1行第2列的单元格被选中
6.更多更详细的见源码
地址:https://github.com/developerzjy/AndroidTableView