用CAB自定义ListView中的多个select

经过几天的阅读和尝试后,我放弃并寻求帮助。

我正在使用ActionBarSherlock。 </ edit>

我想实现的是:一个ListView,每行都有一个自定义的布局,用户可以select多个列表项。 选定的列表项目应具有不同的背景颜色。 当至lessselect一个项目时,应显示一个上下文操作栏(CAB)。 它应该看起来或多或less像GMail应用程序中的多个电子邮件select。 唯一的区别是,在Gmail应用程序的select是通过单击一行的checkbox来完成,而我不想有一个checkbox,但是应该select一行,无论用户点击的地方。 GMail应用程序中的多个选择

我所尝试的:按照这个教程 ,当检查状态被切换时,使用带有逻辑的Checkable行布局来更改背景颜色,除了我无法在ListView上注册像OnItemClickListener这样的单击监听器来显示CAB 。 既无法为每行查看提供点击侦听器,因为这阻止了更改所选项目的背景颜色。 我也尝试像这样添加一个MultiChoiceModeListener到ListView

listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); listView.setMultiChoiceModeListener(new MultiChoiceModeListener() { //.. }); 

同样的结果,没有背景颜色的变化。

我在找什么 :提示或教程或示例代码如何做到这一点。 如果你需要一些代码片段来帮助,让我知道。

看看代码是否可以帮助你(这基本上是一个ListActivity与一个自定义适配器来保存检查项目的状态(+不同的背景)):

 public class CABSelection extends ListActivity { private ArrayList<String> mItems = new ArrayList<String>(); private SelectionAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); for (int i = 0; i < 24; i++) { mItems.add("Name" + i); } // R.layout.adapters_cabselection_row is a LinearLayout(with green // background(#99cc00)) that wraps an ImageView and a TextView mAdapter = new SelectionAdapter(this, R.layout.adapters_cabselection_row, R.id.the_text, mItems); setListAdapter(mAdapter); getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() { private int nr = 0; @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.cabselection_menu, menu); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { StringBuilder sb = new StringBuilder(); Set<Integer> positions = mAdapter.getCurrentCheckedPosition(); for (Integer pos : positions) { sb.append(" " + pos + ","); } switch (item.getItemId()) { case R.id.edit_entry: Toast.makeText(CABSelection.this, "Edited entries: " + sb.toString(), Toast.LENGTH_SHORT).show(); break; case R.id.delete_entry: Toast.makeText(CABSelection.this, "Deleted entries : " + sb.toString(), Toast.LENGTH_SHORT).show(); break; case R.id.finish_it: nr = 0; mAdapter.clearSelection(); Toast.makeText(CABSelection.this, "Finish the CAB!", Toast.LENGTH_SHORT).show(); mode.finish(); } return false; } @Override public void onDestroyActionMode(ActionMode mode) { nr = 0; mAdapter.clearSelection(); } @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { if (checked) { nr++; mAdapter.setNewSelection(position, checked); } else { nr--; mAdapter.removeSelection(position); } mode.setTitle(nr + " rows selected!"); } }); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { l.setItemChecked(position, !mAdapter.isPositionChecked(position)); } private class SelectionAdapter extends ArrayAdapter<String> { private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>(); public SelectionAdapter(Context context, int resource, int textViewResourceId, List<String> objects) { super(context, resource, textViewResourceId, objects); } public void setNewSelection(int position, boolean value) { mSelection.put(position, value); notifyDataSetChanged(); } public boolean isPositionChecked(int position) { Boolean result = mSelection.get(position); return result == null ? false : result; } public Set<Integer> getCurrentCheckedPosition() { return mSelection.keySet(); } public void removeSelection(int position) { mSelection.remove(position); notifyDataSetChanged(); } public void clearSelection() { mSelection = new HashMap<Integer, Boolean>(); notifyDataSetChanged(); } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = super.getView(position, convertView, parent);//let the adapter handle setting up the row views v.setBackgroundColor(Color.parseColor("#99cc00")); //default color if (mSelection.get(position) != null) { v.setBackgroundColor(Color.RED);// this is a selected position so make it red } return v; } } } 

R.layout.adapters_cabselection_row是一个绿色背景的行(一个非常简单的)的自定义布局:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#99cc00" > <ImageView android:id="@+id/imageView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" /> <TextView android:id="@+id/the_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ffffff" android:textSize="17sp" android:textStyle="bold" /> </LinearLayout> 

R.menu.cabselection_menu是一个带有3个选项(编辑,删除,完成CAB)的菜单文件,除了popupToast消息外,

 <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/edit_entry" android:icon="@android:drawable/ic_menu_edit" android:title="Edit!"/> <item android:id="@+id/delete_entry" android:icon="@android:drawable/ic_menu_delete" android:title="Delete!"/> <item android:id="@+id/finish_it" android:icon="@android:drawable/ic_menu_crop" android:title="Get me out!"/> </menu> 

我认为最简单的方法就是申请

android:background="android:attr/activatedBackgroundIndicator"

哪个布局是你将要点击的布局。

这将突出显示使用时select的布局

 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); 

无论如何,为我工作

如果您要支持API级别<11,则使用ActionBarSherlock,Luksprog的答案中使用的MultiChoiceModeListener尚不可用。

解决方法是使用onItemClickListener。

列表设置:

 listView = (ListView) timeline.findViewById(android.R.id.list); listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); listView.setItemsCanFocus(false); listView.setAdapter(new ListAdapter(getActivity(), R.layout.cleaning_list_item, items)); 

ListFragment或ListActivity的监听器:

 @Override public void onListItemClick(ListView l, View v, int position, long id) { SparseBooleanArray checked = listView.getCheckedItemPositions(); boolean hasCheckedElement = false; for (int i = 0; i < checked.size() && !hasCheckedElement; i++) { hasCheckedElement = checked.valueAt(i); } if (hasCheckedElement) { if (mMode == null) { mMode = ((SherlockFragmentActivity) getActivity()).startActionMode(new MyActionMode()); mMode.invalidate(); } else { mMode.invalidate(); } } else { if (mMode != null) { mMode.finish(); } } } 

其中MyActionMode是ActionMode.Callback的一个实现:

 private final class MyActionMode implements ActionMode.Callback { /* ... */ }