Android 使用 CAB 在自定义 ListView 中进行多项选择

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10598348/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 04:17:29  来源:igfitidea点击:

Multiple selection in custom ListView with CAB

androidandroid-listview

提问by Konsumierer

After reading and try'n'error for days, I′m giving up and ask for help.

在阅读并尝试了几天后,我放弃并寻求帮助。

< edit > I am using ActionBarSherlock. < /edit >

< 编辑 > 我正在使用 ActionBarSherlock。</编辑>

What I want to achieve:A ListView with a custom layout for each row, where the user can select multiple list items. A selected list item should have a different background color. When there is at least one item selected, a contextual action bar (CAB) should be shown. It should look more or less like the multiple selection of emails in the GMail app. The only difference is that in the gmail app the selection is done by clicking the checkbox of a row, whereas I don′t want to have a checkbox, but a row should be selected no matter, where the user clicks. Multiple selection in GMail app

我想要实现的目标:每行都有一个自定义布局的 ListView,用户可以在其中选择多个列表项。选定的列表项应具有不同的背景颜色。当至少选择了一项时,应显示上下文操作栏 (CAB)。它应该或多或少类似于 GMail 应用程序中的多选电子邮件。唯一的区别是,在gmail 应用程序中,选择是通过单击一行的复选框来完成的,而我不想有一个复选框,但是无论用户单击何处,都应该选择一行。 GMail 应用中的多项选择

What I tried:Following this tutorial, using a Checkable row layout with some logic to change the background color when the check state was toggled, I got everything working except that I could not register a click listener like OnItemClickListener on the ListView to show the CAB. Neither providing a click listener for each row View helped because this prevented to change the background color of the selected items. I also tried adding a MultiChoiceModeListener to the ListView like that

我尝试过的内容:按照本教程,使用带有一些逻辑的 Checkable 行布局来在切换检查状态时更改背景颜色,除了无法在 ListView 上注册像 OnItemClickListener 这样的单击侦听器以显示 CAB 之外,一切正常. 为每行 View 提供点击监听器都没有帮助,因为这阻止了更改所选项目的背景颜色。我还尝试将 MultiChoiceModeListener 添加到 ListView 中

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

With the same result, no background color change.

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

What I am looking for: A hint or a tutorial or sample code how to do this. If you need some code snippets to help, let me know.

我在寻找什么:如何做到这一点的提示或教程或示例代码。如果您需要一些代码片段来提供帮助,请告诉我。

采纳答案by Konsumierer

Using ActionBarSherlock the MultiChoiceModeListenerused in Luksprog′s answer is not yet available if you want to support API level < 11.

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

A workaround is to use the onItemClickListener.

一种解决方法是使用 onItemClickListener。

List setup:

列表设置:

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));

Listener of ListFragment or ListActivity:

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();
        }
    }
}

Where MyActionMode is an implementation of ActionMode.Callback:

其中 MyActionMode 是 ActionMode.Callback 的实现:

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

回答by Luksprog

See if the code helps you(it's basically a ListActivitywith a custom adapter to hold the status of checked items(+ different background)):

看看代码是否对你有帮助(它基本上是一个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;
        }

    }

}

The R.layout.adapters_cabselection_rowis a custom layout for the row(a very simple one) with a green background:

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_menuis a menu file with 3 options(edit, delete, finish the CAB) which don't do anything except pop a Toastwith a message regarding the rows selected:

R.menu.cabselection_menu是一个带有 3 个选项(编辑、删除、完成 CAB)的菜单文件,除了弹出一个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>

回答by SeanSWatkins

I think the easiest way is to apply

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

android:background="android:attr/activatedBackgroundIndicator"

android:background="android:attr/activatedBackgroundIndicator"

To which ever layout is the one you will be clicking.

您将单击哪个布局。

This highlights the layout when selected using

当使用选择时,这会突出显示布局

listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);

worked for me anyway

无论如何都为我工作