退出select模式后,ListViewselect保持不变

我有一个ListView子类,当上下文操作栏(CAB)处于活动状态时,允许进行select。 CAB被设置为onItemLongClick事件的callback:

 public boolean onCreateActionMode(ActionMode mode, Menu menu) { // Inflate a menu resource providing context menu items MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(context_menu, menu); getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); return true; } 

这很好,ListView按预期工作,当前选定的项目在触摸时保持突出显示。

当我closuresCAB时, 我希望ListView恢复正常(即触摸模式) 。 问题是最后select的项目无限期地保持高亮显示,无论我尝试清除它的方法:

 public void onDestroyActionMode(ActionMode mode) { //Unselect any rows ListView lv = getListView(); lv.clearChoices(); // Has no effect lv.setChoiceMode(ListView.CHOICE_MODE_NONE); // Has no effect on the highlighted item lv.setFocusable(false); // Has no effect lv.setSelection(0); // Has no effect mActionMode = null; } 

有什么build议么?

问题的主要原因是,一旦ListViewselect模式切换到CHOICE_MODE_NONE ,框架将优化清除操作,因为它不再支持“select”。 通过手动清除select状态,然后以延迟的方式设置模式,框架将轮到在将模式转换为CHOICE_MODE_NONE之前清除状态,从而改进了上述解决方法。

 final ListView lv = getListView(); lv.clearChoices(); for (int i = 0; i < lv.getCount(); i++) lv.setItemChecked(i, false); lv.post(new Runnable() { @Override public void run() { lv.setChoiceMode(ListView.CHOICE_MODE_NONE); } }); 

我面临同样的问题,因为要求布局并不能解决我的问题,要么我实施了一些适合我的黑客攻击。 也许这是相同的问题,因为我在CHOICE_MODE_SINGLECHOICE_MODE_NONE之间切换。

当动作模式结束时,我正在调用这个代码片段。 clearChoices确保所有项目不再被检查(内部)。 对视图的迭代确保所有当前可见的视图都被重置,而不再被检查。

 mListView.clearChoices(); for (int i = 0; i < mListView.getChildCount(); i++) { ((Checkable) mListView.getChildAt(i)).setChecked(false); } mListView.setChoiceMode(ListView.CHOICE_MODE_NONE); 

查看ListView源代码,解决此问题的唯一方法是将ListView设置为CHOICE_MODE_NONE,然后重新分配ListAdapter(清除内部select列表而不pipeselect模式)

即在ListFragment / ListActivity

 getListView().setChoiceMode(ListView.CHOICE_MODE_NONE); getListView().setAdapter(getListAdapter()) 

我在API Level 17遇到这个问题,并通过下面的方法解决了这个问题:

 listView.clearChoices(); listView.invalidateViews(); 

对我来说,似乎接受的答案是不工作的隐形物品,并不需要打电话

 for (int i = 0; i < lv.getCount(); i++) lv.setItemChecked(i, false); 

相反,只是打电话

 lv.requestLayout(); 

为了彻底解决我的问题,我打电话

 lv.clearChoices(); lv.requestLayout(); 

onDestroyActionMode()

并打电话

 lv.setItemChecked(position, false) 

onItemClick()时,它不在ActionMode中

但是,我没有确认是否调用setItemChecked()会导致一些性能问题

这已被logging为AOSP错误 ,但由于任何原因被标记为过时。

通常你会期望这个工作:

 getListView().clearChoices(); getListView().setChoiceMode(ListView.CHOICE_MODE_NONE); 

不幸的是,它不。 在下一个布局过程中将设置select模式推迟为none将会起作用:

 getListView().clearChoices(); getListView().post(new Runnable() { @Override public void run() { getListView().setChoiceMode(ListView.CHOICE_MODE_NONE); } }); 

我已经尝试了上面讨论的所有方法,但没有一个为我工作。 最后,我决定应用以下解决方法。 关键的想法是,

在多模式期间,不是重复使用“caching”视图,而是创build一个全新的视图。 效率不高,但至less“部分”解决了我的问题。

这是我自定义的ArrayAdapter的代码

 @Override public View getView(int position, View convertView, ViewGroup parent) { // Key to solve this problem. When we are in multimode, we will not reusing the cached view. View rowView = this.multimode ? null : convertView; if (rowView == null) { LayoutInflater inflater = activity.getLayoutInflater(); rowView = inflater.inflate(R.layout.watchlist_row_layout, null); ViewHolder viewHolder = new ViewHolder(); viewHolder.textView0 = (TextView) rowView.findViewById(R.id.text_view_0); viewHolder.textView1 = (TextView) rowView.findViewById(R.id.text_view_1); viewHolder.textView2 = (TextView) rowView.findViewById(R.id.text_view_2); rowView.setTag(viewHolder); } 

另外,我觉得在ActionMode.Callback中有以下代码更安全,但我不确定它有多大的帮助。

  @Override public void onDestroyActionMode(ActionMode mode) { MyFragment.this.myArrayAdapter.setMultimode(false); // http://stackoverflow.com/questions/9754170/listview-selection-remains-persistent-after-exiting-choice-mode // Using View.post is the key to solve the problem. final ListView listView = MyFragment.this.getListView(); listView.clearChoices(); for (int i = 0, ei = listView.getChildCount(); i < ei; i++) { listView.setItemChecked(i, false); } listView.post(new Runnable() { @Override public void run() { listView.setChoiceMode(ListView.CHOICE_MODE_NONE); } }); actionMode = null; } 

边注

使用MultiChoiceModeListener和CHOICE_MODE_MULTIPLE_MODAL会使这个bug消失。 但是,对于低于API级别11的设备将无法使用此解决scheme。

我知道这已被回答,但上面的答案仍然给我的ListView维护的caching/循环视图的问题,没有更新它的状态时滚动回视图。 所以,上面的解决scheme稍微改变为:

  lv.clearChoices(); ArrayList<View> list = new ArrayList<View>(); lv.reclaimViews(list); for (View view : list) { ((Checkable) view).setChecked(false); } lv.setChoiceMode(lv.CHOICE_MODE_NONE); 

这比使用getChildAt(i)更好,因为该方法jusg给你当前可见的视图,并不考虑内部caching视图,这是不可见的。

我发现在这里工作的唯一两种方法(API 19)是:

  • 重置列表适配器,这是不可取的,因为它回到列表的顶部;
  • new Runnable中将select模式设置为CHOICE_MODE_NONE

如果在不使用listView.post(new Runnable())情况下更改了select模式,则不起作用。 任何人都可以向我解释为什么这是?

对不予评论的道歉; 我没有名誉。

谢谢。

不知道这是不是太晚,只是想分享。 我创build了一个意图到同一个页面,以便一旦捕获点击的数据,它重新创build一个新的页面,没有任何点击持久性。

不是一个错误。 该行为是支持Android的多个HID所必需的。 所以要显示select状态,你只需要设置listview的select模式和背景来支持“list item layout”的select状态,比如:

android:background="?android:attr/activatedBackgroundIndicator"

供参考: http : //android-developers.blogspot.mx/2008/12/touch-mode.html