Gmail-подобный ListView с флажками (и с помощью ActionBar)

Я пытаюсь воссоздать то, что Google сделал с ListView в приложении Gmail. В частности, я хотел бы, чтобы каждый элемент списка включал CheckBox и два TextViews (один поверх другого). Мне нужны слушатели, когда CheckBox проверен (или щелкнул), и когда в другом месте в элементе списка щелкнут. Наконец, я бы хотел, чтобы ActionBar отражал, что элементы выбраны и предоставляют такие параметры, как «Выбрать все», «Выбрать« Нет »и т. Д. (См. Этот снимок экрана ).

Введите описание изображения здесь

Пока, вот макет, который я придумал.

<?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:orientation="horizontal" > <CheckBox android:id="@+id/checkBox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|center_horizontal" /> <LinearLayout android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="6dp" android:focusable="true" android:clickable="true" > <TextView android:id="@+id/titleTextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="16sp" /> <TextView android:id="@+id/dateTextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="12sp" /> </LinearLayout> </LinearLayout> 

Это отображает все правильно, но мне нужно указать, как настроить слушателей для двух представлений ( @ + id / checkBox и @ + id / linearLayout1 ). Я просмотрел демоверсию List16 API , но они используют макет simple_list_item_activated_1, и я не уверен, что такое XML для этого. Как показывает их код, я создал класс ModeCallback, который реализует ListView.MultiChoiceModeListener, и я установил режим выбора ListView в CHOICE_MODE_MULTIPLE_MODAL, но я не знаю, как заставить CheckBox в моем макете работать с этим.

Кто-нибудь успешно скопировал поведение ListView в приложении Gmail? Я искал довольно много и не мог придумать ничего (несмотря на то, что некоторые другие задавали похожие вопросы, как этот – большинство ответов просто указывают на эту же демонстрационную версию API).

Кроме того, для контекста я загружаю данные из базы данных SQLite в список, и я создал свой собственный адаптер курсора (который отлично работает). У меня есть ощущение, что мне нужно настроить слушателей в этом классе в методах newView () и bindView (), но все, что я пробовал, не сработало.

Есть идеи?

Solutions Collecting From Web of "Gmail-подобный ListView с флажками (и с помощью ActionBar)"

Режим на рисунке называется режимом действия. Если вы используете свой собственный вид строки и пользовательский адаптер, вам не нужно использовать CHOICE_MODE_MULTIPLE_MODAL для запуска режима действия. Я попробовал один раз и не смог, и я подозреваю, что он используется для встроенного адаптера.

Чтобы вызвать режим действия самостоятельно в вашем коде, вызовите метод startActionMode в любом методе прослушивания любого из ваших представлений, пусть это будет checkbox, textview или что-то в этом роде. Затем вы передаете ModeCallback в качестве параметров и выполняете любую операцию, которую хотите сделать в классе ModeCallback.

Я не думаю, что это будет работать на pre-3.0 Android.

Вот краткий пример. У меня есть расширяемая активность в списке и вызывается меню режима действия, когда пользователь проверяет / снимает флажок, и вот мой метод getChildView в моем настраиваемом классе адаптера:

 public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { if (convertView == null) { LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.childrow, null); } CheckBox cb = (CheckBox)convertView.findViewById(R.id.row_check); cb.setChecked(false); // Initialize cb.setTag(groupPosition + "," + childPosition); cb.setFocusable(false); // To make the whole row selectable cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { String tag = (String)buttonView.getTag(); String[] pos = tag.split(","); if (isChecked) { if (mActionMode == null) mActionMode = startActionMode(mMultipleCallback); } else { if (mActionMode != null) { // Only operate when mActionMode is available mActionMode.finish(); mActionMode = null; } } } }); TextView tvTop = (TextView)convertView.findViewById(R.id.row_text_top); TextView tvBottom = (TextView)convertView.findViewById(R.id.row_text_bottom); tvTop.setText(mChildren.get(groupPosition).get(childPosition)); tvBottom.setText(mChildrenSize.get(groupPosition).get(childPosition)); return convertView; } 

Это будет работать в SDK 7 (Android 2.1) и выше. (Вместе с SherlockActionBar)

Totaly mimic gmail listbox.

Я переопределяю onTouchEvent, поэтому нажмите в левом углу, активирует режим выбора; Лучше, чем пытаться щелкнуть на крошечной сумке.

Я переопределяю performItemClick, поэтому нажатие не влево будет действовать как регулярное действие пресса.

Я переопределяю setItemChecked, поэтому он будет обновлять mActionMode по мере необходимости.

 public class SelectListView extends ListView { private SherlockFragmentActivity mActivity; ActionMode mActionMode; public SelectListView(Context context) { this( context, null, 0); } public SelectListView(Context context, AttributeSet attrs) { this( context, attrs, 0); } public SelectListView(Context context, AttributeSet attrs, int defStyle) { super( context, attrs, defStyle ); setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); mActivity = (SherlockFragmentActivity) context; } @Override public boolean performItemClick(View view, int position, long id) { OnItemClickListener mOnItemClickListener = getOnItemClickListener(); if (mOnItemClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); if (view != null) view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); mOnItemClickListener.onItemClick(this, view, position, id); return true; } return false; } boolean mSelectionMode = false; int mStartPosition; @Override public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getAction(); final int x = (int) ev.getX(); final int y = (int) ev.getY(); if (action == MotionEvent.ACTION_DOWN && x < getWidth() / 7) { mSelectionMode = true; mStartPosition = pointToPosition(x, y); } if (!mSelectionMode) return super.onTouchEvent(ev); switch (action) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: if (pointToPosition(x, y) != mStartPosition) mSelectionMode = false; break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: default: mSelectionMode = false; int mItemPosition = pointToPosition(x, y); if (mStartPosition != ListView.INVALID_POSITION) setItemChecked(mItemPosition, !isItemChecked(mItemPosition)); } return true; } @Override public void setItemChecked(int position, boolean value) { super.setItemChecked(position, value); // boolean r = getAdapter().hasStableIds(); int checkedCount = getCheckItemIds().length; if (checkedCount == 0) { if (mActionMode != null) mActionMode.finish(); return; } if (mActionMode == null) mActionMode = mActivity.startActionMode(new ModeCallback()); mActionMode.setTitle(checkedCount + " selected"); } class ModeCallback implements ActionMode.Callback { @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { menu.add(getResources().getString(R.string.aBar_remove)).setIcon(R.drawable.ic_action_trash) .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return true; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { Toast.makeText(mActivity, "Delted items", Toast.LENGTH_SHORT).show(); mode.finish(); return true; } @Override public void onDestroyActionMode(ActionMode mode) { mActionMode = null; clearChecked(); } } public void clearChecked() { SparseBooleanArray CItem = getCheckedItemPositions(); for (int i = 0; i < CItem.size(); i++) if (CItem.valueAt(i)) super.setItemChecked(CItem.keyAt(i), false); } } 

Вы можете использовать любой адаптер списка, который вам нужен.

Если у вас есть флажок в списке list_item_layout, вам необходимо расширить свой адаптер следующим образом:

 ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, R.layout.simple_list_item_multiple_choice, R.id.text1, Cheeses.sCheeseStrings) { @Override public View getView(int position, View convertView, ViewGroup parent) { View v = super.getView(position, convertView, parent); CheckBox checkBox = (CheckBox) v.findViewById(R.id.CheckBox); checkBox.setChecked(((ListView)parent).isItemChecked(position)); return v; } }; 

Не забудьте использовать android: background = "? Attr / activatedBackgroundIndicator" в вашем list_item_layout.xml

В дополнение к ответу tocnbuff410 используйте следующий код для обновления отмеченных элементов count

 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { ++checkBoxCount; } else { --checkBoxCount; } ... if (mActionMode != null) { mActionMode.setSubtitle(checkBoxCount + " item(s) selected."); } 

Я могу подтвердить, что следующий код не будет работать с флажками пользовательских списков просмотров. Однако долгое нажатие продолжало бы работать:

 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); listView.setMultiChoiceModeListener(new ModeCallback()); 

Выбор флажка в пользовательском ListView не приведет к срабатыванию actionmode. Только встроенные ListViews, например расширение ListActivity, автоматически это сделает.