问题源于 AbsListView.java 中这段不灵活的代码,它在取消选择最后一项时无条件地关闭 ActionMode:
class MultiChoiceModeWrapper implements MultiChoiceModeListener {
...
@Override
public void onItemCheckedStateChanged(ActionMode mode,
int position, long id, boolean checked) {
mWrapped.onItemCheckedStateChanged(mode, position, id, checked);
// If there are no items selected we no longer need the selection mode.
if (getCheckedItemCount() == 0) {
mode.finish();
}
}
}
由于 AbsListView 没有提供任何钩子来合法地阻止这种严厉的行为,因此当上面的代码调用它时,您不得不诉诸丑陋的技巧,即从您自己的 AbsListView 子类中从 getCheckedItemCount 返回一个虚假值:
public class ActionModeHackGridView extends GridView {
...
@Override
public int getCheckedItemCount() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
String name = ActionModeHackGridView.class.getName();
for (int i = 0; i < stackTrace.length; i++) {
// First find this method in the stack
if (stackTrace[i].getClassName().equals(name)
&& stackTrace[i].getMethodName().equals("getCheckedItemCount")) {
// ...then examine the caller of this method
if (stackTrace[i + 1].getClassName().equals(
"android.widget.AbsListView$MultiChoiceModeWrapper")
&& stackTrace[i + 1].getMethodName().equals("onItemCheckedStateChanged")) {
// Return a non-zero value so AbsListView doesn't dismiss the ActionMode
return 1;
}
break;
}
}
return super.getCheckedItemCount();
}
}
您可以在任何 AbsListView 子类(例如 ListView)中使用相同的 hack。