如何从ListView中获取所有已选项目?

45

我有几个问题一直没有弄清楚。

我正在尝试从 ListView 中获取所有已选中的元素,但是:

  1. 如果我选中然后取消选中一个元素,它会被 getCheckedItemPositions() 函数返回为“已选中”

  2. 我不知道如何遍历这些已选中的元素:

    SparseBooleanArray checked = list.getCheckedItemPositions();
    

请看一下这些链接,也许会有帮助: http://stackoverflow.com/questions/4019308/android-list-getcheckeditempositions-always-returns-null https://dev59.com/aG865IYBdhLWcg3wFqdV https://dev59.com/u1HTa4cB1Zd3GeqPQ1-A - rBaggio
1
从API级别11开始,您可以使用list.getCheckedItemCount(); - Rajkiran
10个回答

81

使用 SparseBooleanArray 的其他答案几乎是正确的,但它们缺少一个重要的事情:SparseBooleanArray.size() 有时只会返回 true 值的计数。一个正确的实现需要遍历整个列表中的所有项目:

SparseBooleanArray checked = list.getCheckedItemPositions();

for (int i = 0; i < list.getAdapter().getCount(); i++) {
    if (checked.get(i)) {
        // Do something
    }
}

7
具有讽刺意味的是,这个唯一正确(且合理)的答案却没有得到一票。 - mseddon
1
为什么需要遍历整个列表?getCheckedItemPositions()方法不是设计用来避免这种情况的吗?为什么不直接迭代由getCheckedItemPositions()方法已经为您选择的项目Foo objectAtCheckedRow = null; for (int i = 0; i < positions.size(); i++) { /*positions.size() == 2*/ objectAtCheckedRow = adapter.getItem(positions.keyAt(i)); /*在此处对对象执行重要操作*/ } - Sergey
@Sergey 我不是在说使用过时的SparseBooleanArray;我是说如果用户在您调用getCheckedItemPositions()之前选中一个项目,然后取消选中它,它仍然可能出现在检索到的数组中,并且其值为false。如果布尔状态始终为true,则该调用可以简单地返回已选位置的int数组。 - Jarett Millard
1
@Jarett 所以,我的代码是错误的,它不会产生与你的相同的结果。我必须检查从SparseBooleanArray返回的每个项:for (int i = 0; i < positions.size(); i++) { if (positions.valueAt(i)) { Foo objectAtCheckedRow = adapter.getItem(positions.keyAt(i)); /*在此处对对象执行重要操作*/ } }但我仍然认为没有必要遍历整个列表。 - Sergey
2
实际上我遇到了一个问题,只有这个答案是正确的。我有一个多达10个复选框的列表。如果最后两个被选中,'getCheckedItemPositions()'将返回整个列表,但如果我要求大小,它将返回2,因为只有2个项目被选中,并且仅迭代前两个项目,从未达到选中的项目。只有通过像Jarett所演示的从ListAdapter获取大小才能迭代整个列表。这应该被标记为正确答案。 - ckn
显示剩余8条评论

11

这是我用来解决问题的方法:

public class MyAdapter extends BaseAdapter{
    public HashMap<String,String> checked = new HashMap<String,String>();
....
    public void setCheckedItem(int item) {


        if (checked.containsKey(String.valueOf(item))){
            checked.remove(String.valueOf(item));
        }

        else {
            checked.put(String.valueOf(item), String.valueOf(item));
        }
    }
        public HashMap<String, String> getCheckedItems(){
        return checked;
    }
}

设置元素是否被选中:

public class FileBrowser extends Activity implements OnClickListener{        
private ListView list;

    ...
    list.setOnItemClickListener(new OnItemClickListener(){

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int item,
                long id) {

                        BrowserAdapter bla = (BrowserAdapter) parent.getAdapter();
                        bla.setCheckedItem(item);
                    }
    });

然后要从类外部获取已选项目...

MyAdapter bAdapter;    
Iterator<String> it = bAdapter.getCheckedItems().values().iterator();
                    for (int i=0;i<bAdapter.getCheckedItems().size();i++){
                        //Do whatever
                        bAdapter.getItem(Integer.parseInt(it.next());
                    }

希望能帮到有需要的人。


这正好做到了我需要的。如果我想将选择限制为1个项目,我应该如何防范? - AdamMc331
我认为在使用for循环遍历整个集合时,除非你执行it.next() - 1,否则它不会起作用。通过执行it.next(),如果checkeditems列表仅包含1个项目,则会抛出NoSuchElementException异常;如果它有多个项目,则第一个项目将被跳过。 - Willy

8

Jarett的回答很好,但这个方法应该会更快,因为它只检查在稀疏数组中存在于基础数组中的元素(只有这些元素可能是真的):

SparseBooleanArray checkedItemPositions = listView.getCheckedItemPositions();
    final int checkedItemCount = checkedItemPositions.size();
    for (int i = 0; i < checkedItemCount; i++) {
        int key = checkedItemPositions.keyAt(i);
        if (checkedItemPositions.get(key)) {
            doSomething(key);
        } else {
            // item was in the sparse array, but not checked.
        }
    }

专业提示:查看SparseBooleanArray源代码,它是一个非常简单的类:

http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/4.0.3_r1/android/util/SparseBooleanArray.java/?v=source


6

我的大脑不喜欢循环遍历SparseBooleanArray,而且我也不需要自定义适配器,所以以下代码对我来说更加直观:

  1. Don't forget to use CHOICE_MODE_MULTIPLE in onCreate():

    getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

  2. Use the following method to get an ArrayList of them:

    // This example is to get an ArrayList of names (Strings)
    protected ArrayList<String> getNames() {
        ArrayList<String> names = new ArrayList<String>();
    
        for (int i = 0; i < getListView().getCount(); i++) {
            if (getListView().isItemChecked(i)) {
                // Do whatever you need to in here to get data from
                // the item at index i in the ListView
                names.add(mUsers.get(i).getName());
            }
        }
    
        return names;
    } 
    

2
这很完美。没有任何理由让任何人陷入 SparseBooleanArray 的地狱洞中。 - David

6
您可以使用for循环和SparseBooleanArray的size()和get(index)方法来遍历SparseBooleanArray。
编辑3/2/2014: 有人指出SparseBooleanArray的size()方法返回已选中值的数量,而不是数组的真实长度,因此我已修复了我的答案以解决这个问题。本质上它是相同的,只是我们不再迭代数组的长度,而是迭代直到找到所有已选项目。由于我们只关心已选项目的数量,所以使用这种方法时,我们可能实际上并没有到达数组的末尾(我们将看不到最后一个已选项目之后的任何内容)。
SparseBooleanArray checked = list.getCheckedItemPositions();

int numChecked = checked.size();

for (int i = 0; numChecked > 0; i++){
    if (checked.get(i)){
        //the item at index i is checked, do something
        numChecked--; //We found a checked item, so decrement the number of checked items remaining
    }
    else
        //the item is not checked, do something else
}

1
SparseBooleanArray.size() 只会返回 true 值的数量,而不是所有值的数量。 - Richard
SparseBooleanArray.size() ... "返回此 SparseBooleanArray 当前存储的键值映射数。" 来自 http://developer.android.com/reference/android/util/SparseBooleanArray.html#size() 。这不一定只是 true 值。 - treesAreEverywhere
3
是的,但是从ListView.getCheckedItemPositions()返回的SparseBooleanArray大小仅等于已选项目的数量。未选项目将不会显示在SparseBooleanArray中。 - Jarett Millard

2
 final long[] checkedIds = lv.getCheckItemIds();
            for (int i = 0; i < checkedIds.length; i++) {
                Log.d("checkedIds", "id checked: " + checkedIds[i]);
            }

2
注意:此方法已被弃用,您应该使用getCheckedItemIds()代替(从API 8 / Android 2.2可用)。 - Timmmm

1

刚看到这个问题,我也遇到了同样的问题。

使用SparseBooleanArray有一个更简单的解决方案,可以精确计算选中的项目数量。 这是我的onClick过程:

@Override
public void onClick(View v) {
switch(v.getId()) {
  case R.id.button:
    SparseBooleanArray a = listView.getCheckedItemPositions();
    if(checked(vArray)>0) {
            String vCheckedList = "";
            for (int i = 0; i < nLength; i++) {
                if (a.valueAt(i) && i < nLength-1 && a.size()>1)
                    vCheckedList += listView.getAdapter().getItem(vArray.keyAt(i))+"\n";
                else if (a.valueAt(i))
                    vCheckedList += listView.getAdapter().getItem(vArray.keyAt(i));
            }
            Toast.makeText(getApplicationContext(), vCheckedList+ " is checked", Toast.LENGTH_SHORT).show(); 
            a.clear();
        } else
            Toast.makeText(getApplicationContext(), "No Item is Selected", Toast.LENGTH_SHORT).show();
        break;
    default:
        break;
        }
}

checked 方法:

private int checked(SparseBooleanArray vArray) {
    int vCounter = 0;
    for(int i=0;i<vArray.size(); i++)
        if(vArray.valueAt(i))
            vCounter++;
    return vCounter;

}

这将解决所选项目的两个问题。


1

我曾经遇到过同样的问题,这是我的解决方案,使用 SparseBooleanArray

SparseBooleanArray checkedPositions = lv.getCheckedItemPositions ();
int size = checkedPositions.size ();
for (int i=0 ; i<size ; i++) {
     // We get the key stored at the index 'i'
     int key = checkedPositions.keyAt (i);
     // We get the boolean value with the key
     Log.i (Tag, "checkedPositions(" + key + ")=" + checkedPositions.get (key));
}

0

这是我使用的完整解决方案。

其中pos是Recyclerview项目的位置

SparseBooleanArray selected = new SparseBooleanArray();

//OnClick listener here or whatever you use to check or uncheck an item
if (selected.get(pos, false)) {
        selected.delete(pos);
    } else {
        selected.put(pos, true);
    }

selected.size() 将显示有多少项被选中

selected.get(pos) 如果已选中,则返回 true

如下所述,以下代码将迭代所有已选择的项目:

for (int i = 0; i < list.getAdapter().getCount(); i++) {
    if (selected.get(pos)) {
        // Do stuff
    }
}

0

以下是我从RecyclerView适配器中获取已选项的方法

fun getAllCheckedItems(outList){
         for (position in spareBooleanArray.keyIterator()) {
            outList.add(mList.get(position)
        }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接