Подтвердить что ты не робот

Множественный выбор в пользовательском ListView с CAB

После прочтения и try'n'error в течение нескольких дней я отказываюсь и прошу помощи.

< редактировать > Я использую ActionBarSherlock. </edit>

Что я хочу достичь: ListView с настраиваемым макетом для каждой строки, где пользователь может выбрать несколько элементов списка. Выбранный элемент списка должен иметь другой цвет фона. Когда есть хотя бы один выбранный элемент, должна отображаться панель контекстного действия (CAB). Он должен выглядеть более или менее похожим на множественный выбор писем в приложении GMail. Единственное различие заключается в том, что в приложении gmail выбор сделан, щелкнув флажок строки, тогда как я не хочу иметь флажок, но строка должна быть выбрана независимо от того, где пользователь нажимает. Multiple selection in GMail app

Что я пробовал: После этот учебник, используя макет Checkable row с некоторой логикой для изменения цвета фона при переключении состояния проверки, я получил все, кроме Я не мог зарегистрировать прослушиватель кликов, такой как OnItemClickListener в ListView, чтобы показать CAB. Также не предоставлял прослушиватель кликов для каждой строки View, потому что это предотвратило изменение цвета фона для выбранных элементов. Я также попытался добавить MultiChoiceModeListener в ListView, подобный этому

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

С тем же результатом цвет фона не меняется.

Что я ищу: подсказка или учебник или пример кода, как это сделать. Если вам нужны некоторые фрагменты кода, чтобы помочь, сообщите мне.

4b9b3361

Ответ 1

Использование ActionBarSherlock MultiChoiceModeListener, используемое в ответе Luksprog, пока недоступно, если вы хотите поддерживать уровень API < 11.

Обходным путем является использование 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 { /* ... */ }

Ответ 2

Посмотрите, помогает ли вам код (в основном 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 - это файл меню с тремя параметрами (редактировать, удалять, заканчивать CAB), которые ничего не делают, кроме pop a Toast с сообщением о выбранных строках:

<?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>

Ответ 3

Я думаю, что самый простой способ - применить

android:background="android:attr/activatedBackgroundIndicator"

К которому когда-либо был выбран макет, который вы нажмете.

Это выделяет макет при выборе с помощью

listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);

работал у меня в любом случае