`
aijuans
  • 浏览: 1568123 次
社区版块
存档分类
最新评论

android ListView 的多选模式

阅读更多

    昨天晚上熬粥,设定六个小时之后熬一个小时的,不知为什么后来变成一个小时之后熬了六个小时,今天早饭就只好改吃锅巴了。j_0064.gif

    在《ListView的单选模式》中,已经知道ListView有多选模式的,事实上我喜欢的作家也不只一个。ListView的多选模式起初写得比较简单,从中便发现了一些问题。

    先看一下布局文件,几乎和先前没怎么变化,只是改掉了ListView的模式而已。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
 
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:onClick="showSelectAuthors"
        android:text="@string/select_authors"
        android:textSize="25sp" />
 
    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:choiceMode="multipleChoice" />
 
</LinearLayout>

    Activity的代码如下,没有用适配器来处理数据,简单使用了ArrayAdapter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.example.choicelistviewtest2;
 
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
 
public class RadioButtonListActivity extends Activity {
 
    private ListView radioButtonList;
    private String[] names = new String[] { "芥川龙之介""三岛由纪夫""川端康成""村上春树",
            "东野圭吾""张爱玲""金庸""钱钟书""老舍""梁实秋""亨利米勒""海明威""菲兹杰拉德",
            "凯鲁亚克""杰克伦敦""小仲马""杜拉斯""福楼拜""雨果""巴尔扎克""莎士比亚""劳伦斯",
            "毛姆""柯南道尔""笛福" };
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        radioButtonList = (ListView) findViewById(R.id.list);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_multiple_choice, names);
        radioButtonList.setAdapter(adapter);
    }
 
    public void showSelectAuthors(View v) {
        long[] authorsId = radioButtonList.getCheckItemIds();
 
        String name = "";
        String message;
        if (authorsId.length > 0) {
            // 用户至少选择了一位作家
            for (int i = 0; i < authorsId.length; i++) {
                name += "," + names[(int) authorsId[i]];
            }
            // 将第一个作家前面的“,”去掉
            message = name.substring(1);
        else {
            message = "请至少选择一位作家!";
        }
        Toast.makeText(RadioButtonListActivity.this, message, Toast.LENGTH_LONG)
                .show();
    }
 
}

    上面的代码是成功的,程序运行也OK,本以为可以这样结束了,却发现一个问题:

 

 

   long[] authorsId = radioButtonList.getCheckItemIds();

    从图上可以看出“getCheckItemIds()”这个方法是弃用的。事实上ListView的getCheckItemIds()方法所得到数据并不精确,据说在某些Android版本上测试发现,当我们选中ListView的一条Item,然后再次取消,getCheckItemIds()方法还是可以拿到取消的Item的id,即返回的数组中还保留该id。这是源码自己的Bug。

        虽然经过测试,我的手机上没发现这个问题(我的手机Android版本是4.3),但是我想这个方法还是避免使用吧。版本更新后Android推荐使用的是“getCheckedItemIds()”这个方法(注意方法名多加了“ed”),不过这个方法也不是那么好用——“Returns the set of checked items ids. The result is only valid if the choice mode has not been set toCHOICE_MODE_NONE and the adapter has stable IDs. (hasStableIds() == true)。”这个方法返回ListView中被选中Item的id集合。该方法使用有两个条件,第一是ListView的选择模式没有被设置为CHOICE_MODE_NONE(这一点我们满足,我们设置ListView的选择模式为CHOICE_MODE_MULTIPLE),第二是适配器有稳定的 ID(hasStableIds()==true)。这一点是不满足的,诸如ArrayAdapter、SimpleAdapter,不支持稳定的ID(可以通过adapter.hasStableIds()方法查看,返回值为false)。这就要求我们自己创建Adapter,从 hasStableIds()方法中返回true。

    我只好又自定义适配器试了一下这个方法,是成功的,布局文件没有改变,就不再贴了,主要是适配器,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.example.choicelistviewtest3;
 
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
 
public class RadioAdapter extends BaseAdapter {
 
    private String[] authors;
    private Context c;
 
    public RadioAdapter(Context c, String[] authors) {
        super();
        this.c = c;
        this.authors = authors;
    }
 
    @Override
    public int getCount() {
        return authors.length;
    }
 
    @Override
    public Object getItem(int arg0) {
        return null;
    }
 
    @Override
    public long getItemId(int arg0) {
        //返回每一条Item的Id
        return arg0;
    }
 
    @Override
    public boolean hasStableIds() {
        //getCheckedItemIds()方法要求此处返回为真
        return true;
    }
    @Override
    public View getView(int arg0, View arg1, ViewGroup arg2) {
 
        ChoiceListItemView choiceListItemView = new ChoiceListItemView(c, null);
        choiceListItemView.setName(authors[arg0]);
        return choiceListItemView;
    }
 
}

    ChoiceListItemView类与《ListView的单选模式》中的大同小异,只是去掉了Button背景的设置,还原CheckBox原有的样子,因为现在ListView是多选模式。ChoiceListItemView代码与它的XML文件(Item的布局文件)如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.example.choicelistviewtest3;
 
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
import android.widget.Checkable;
import android.widget.LinearLayout;
import android.widget.TextView;
 
public class ChoiceListItemView extends LinearLayout implements Checkable {
 
    private TextView nameTxt;
    private CheckBox selectBtn;
    public ChoiceListItemView(Context context, AttributeSet attrs) {
        super(context, attrs);
 
        LayoutInflater inflater = LayoutInflater.from(context);
        View v = inflater.inflate(R.layout.item_list, thistrue);
        nameTxt = (TextView) v.findViewById(R.id.author);
        selectBtn = (CheckBox) v.findViewById(R.id.radio);
    }
 
    public void setName(String text) {
        nameTxt.setText(text);
    }
 
    @Override
    public boolean isChecked() {
        return selectBtn.isChecked();
    }
 
    @Override
    public void setChecked(boolean checked) {
        selectBtn.setChecked(checked);
    }
 
    @Override
    public void toggle() {
        selectBtn.toggle();
    }
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#fff"
    android:orientation="horizontal" >
 
    <TextView
        android:id="@+id/author"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:padding="10dp"
        android:textSize="20sp" />
    
    <CheckBox
        android:id="@+id/radio"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_gravity="center_vertical"
        android:clickable="false"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:padding="10dp" />
 
</RelativeLayout>

    这样,在主类中就可以使用“getCheckedItemIds()”这个方法了,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.example.choicelistviewtest3;
 
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
 
import android.widget.ListView;
import android.widget.Toast;
 
public class RadioButtonListActivity extends Activity {
 
    private ListView radioButtonList;
    private RadioAdapter adapter;
    private String[] authors = new String[] { "芥川龙之介""三岛由纪夫""川端康成""村上春树",
            "东野圭吾""张爱玲""金庸""钱钟书""老舍""梁实秋""亨利米勒""海明威""菲兹杰拉德",
            "凯鲁亚克""杰克伦敦""小仲马""杜拉斯""福楼拜""雨果""巴尔扎克""莎士比亚""劳伦斯",
            "毛姆""柯南道尔""笛福" };
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_radio_button_list);
 
        radioButtonList = (ListView) findViewById(R.id.list);
        adapter = new RadioAdapter(this, authors);
        radioButtonList.setAdapter(adapter);
    }
 
    public void showSelectAuthors(View v) {
        long[] authorsId = radioButtonList.getCheckedItemIds();
        String name = "";
        String message;
        if (authorsId.length > 0) {
            // 用户至少选择了一位作家
            for (int i = 0; i < authorsId.length; i++) {
                name += "," + authors[(int) authorsId[i]];
            }
            // 将第一个作家前面的“,”去掉
            message = name.substring(1);
        else {
            message = "请至少选择一位作家!";
        }
        Toast.makeText(RadioButtonListActivity.this, message, Toast.LENGTH_LONG)
                .show();
    }
}

    它与choicelistviewtest2包中的RadioButtonListActivity 相比(也就是刚开始的那个RadioButtonListActivity 类),变化很小。显然,如果只是简单地显示一下作家的名字和复选框,而并不需要太多的要求,自定义Adapter实现拥有稳定的ID,这样做事实上是比较麻烦的。下面换一种简单的方法,还是使用ArrayAdapter,只是需要自己来写获取选中Item的ID的方法了,将choicelistviewtest2包中的RadioButtonListActivity增加一个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.example.choicelistviewtest2;
 
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
 
public class RadioButtonListActivity extends Activity {
 
    private ListView radioButtonList;
    private String[] names = new String[] { "芥川龙之介""三岛由纪夫""川端康成""村上春树",
            "东野圭吾""张爱玲""金庸""钱钟书""老舍""梁实秋""亨利米勒""海明威""菲兹杰拉德",
            "凯鲁亚克""杰克伦敦""小仲马""杜拉斯""福楼拜""雨果""巴尔扎克""莎士比亚""劳伦斯",
            "毛姆""柯南道尔""笛福" };
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        radioButtonList = (ListView) findViewById(R.id.list);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_multiple_choice, names);
        radioButtonList.setAdapter(adapter);
    }
 
    public void showSelectAuthors(View v) {
        // long[] authorsId = radioButtonList.getCheckItemIds();
        long[] authorsId = getListSelectededItemIds(radioButtonList);
        String name = "";
        String message;
        if (authorsId.length > 0) {
            // 用户至少选择了一位作家
            for (int i = 0; i < authorsId.length; i++) {
                name += "," + names[(int) authorsId[i]];
            }
            // 将第一个作家前面的“,”去掉
            message = name.substring(1);
        else {
            message = "请至少选择一位作家!";
        }
        Toast.makeText(RadioButtonListActivity.this, message, Toast.LENGTH_LONG)
                .show();
    }
 
    // 避免使用getCheckItemIds()方法
    public long[] getListSelectededItemIds(ListView listView) {
         
        long[] ids = new long[listView.getCount()];//getCount()即获取到ListView所包含的item总个数
        //定义用户选中Item的总个数
        int checkedTotal = 0;
        for (int i = 0; i < listView.getCount(); i++) {
            //如果这个Item是被选中的
            if (listView.isItemChecked(i)) {
                ids[checkedTotal++] = i;
            }
        }
 
        if (checkedTotal < listView.getCount()) {
            //定义选中的Item的ID数组
            final long[] selectedIds = new long[checkedTotal];
            //数组复制 ids
            System.arraycopy(ids, 0, selectedIds, 0, checkedTotal);
            return selectedIds;
        else {
            //用户将所有的Item都选了
            return ids;
        }
    }
 
}

      其中用到了System.arraycopy()这个方法,解释如下:

        public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) src:源数组; srcPos:源数组要复制的起始位置; dest:目的数组; destPos:目的数组放置的起始位置; length:复制的长度。

    这就真正OK了,效果图:

wKioL1RwvlDwvTcbAAgnDZxsVYw757.jpg

wKiom1RwvdWiSrKFAAhUaS6Ff1A876.jpg

 

更多关于 android_intent 的文章请参考 http://www.itmmd.com/tag/android_intent.html

更多关于 android_Listview的文章请参考 http://www.itmmd.com/tag/android_listview.html

2
0
分享到:
评论

相关推荐

    android中listview多选demo

    "android中listview多选demo"就是一个展示如何实现这一功能的示例项目。 在Android的ListView中实现多选,通常涉及到以下几个关键知识点: 1. **CheckedTextView**:这是Android提供的一个内置视图,它继承自...

    ListView多选单选模式

    对于多选模式,我们可以使用`android.widget.CheckBox`。同样,我们需要在适配器的布局文件中包含CheckBox,并在适配器的`getView()`方法中处理用户的点击事件。可以使用`SparseBooleanArray`来存储已选中的项的索引...

    android多选ListView示例

    一、ListView的多选模式 默认情况下,ListView处于单选模式,即每次只能选择一个条目。要启用多选模式,我们需要使用ChoiceMode属性,将其设置为`CHOICE_MODE_MULTIPLE`。这会使得用户可以同时选择多个条目,通常...

    listview多选与单选模式demo

    二、ListView多选模式 1. 多选模式适用于用户可以同时选择多个选项的场景,如文件管理器中的文件选择。在ListView中实现多选,通常使用CheckBox控件,并结合Android的ChoiceMode属性。 2. 设置ListView的...

    android ListView实现多选,批量删除

    在Android开发中,ListView是一种常用的UI组件,用于展示大量数据列表。它允许用户滚动查看信息,而批量删除功能则进一步增强了用户体验,特别是当用户需要处理大量数据时。本篇文章将详细探讨如何在ListView中实现...

    ListView多选,全选,反选,全不选

    多选模式** 要实现多选,我们需要开启ListView的ChoiceMode。在XML布局文件中,可以为ListView设置`android:choiceMode="multipleChoice"`,或者在代码中使用`listView.setChoiceMode(ListView.CHOICE_MODE_...

    android list View多选

    通过以上步骤,我们可以实现一个完整的ListView多选功能。需要注意的是,对于大量数据,应考虑性能优化,避免因频繁更新导致的性能问题。同时,设计合理的UI交互和视觉反馈,将提升用户的使用体验。

    Android ListView多选.rar

    在Android中,我们可以利用ChoiceMode属性来启用多选模式。在ListView上设置`setChoiceMode()`方法,传入`ListView.CHOICE_MODE_MULTIPLE`参数: ```java ListView listView = findViewById(R.id.listView); ...

    listview多选并设置上限

    这样,我们就实现了对ListView多选功能的限制。 此外,如果需要在ListView之外的地方获取用户的选中项,可以调用`selectedItems`列表。同时,为了提高用户体验,我们还可以在ListView的Header或者Footer部分显示...

    最简洁代码实现Listview多选

    这个主题,"最简洁代码实现Listview多选",旨在介绍如何在不写过多冗余代码的情况下,为ListView添加多选模式。 首先,我们需要了解ListView的基础知识。ListView是Android提供的一个视图组件,它能够滚动显示一...

    Android三级目录、ListView单选/GridView单选、ListView多选/GridView多选

    1. **ListView多选**:可以使用CheckBox控件,并配合MultiChoiceModeListener接口。启用ListView的 CHOICE_MODE_MULTIPLE 或 CHOICE_MODE_MULTIPLE_MODAL 模式。在onItemClick()中,切换CheckBox的状态,同时记录...

    listview多选

    通过以上步骤,我们可以实现一个功能完善的ListView多选功能。使用HashMap作为状态存储,不仅易于管理,还能有效避免因数据同步问题导致的错误。在实际开发中,根据项目需求,还可以进一步优化和扩展,如添加长按...

    listview多选demo

    "listview多选demo"通常是指一个示例项目,展示了如何实现ListView中的多选功能。在这个demo中,开发者可能会涉及以下几个关键知识点: 1. **CheckedTextView**:在ListView中实现多选,常用的一种方法是使用...

    ListView多选-点餐系统

    在ListView的XML布局文件中,我们可以设置`android:choiceMode="multipleChoice"`,这会开启多选模式。或者在代码中,可以通过`listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE)`来设置。 接下来,我们需要...

    ActionBar实现listview多选操作

    当多选模式开启时,你需要监听`ListView`的`onItemClick()`事件。在事件回调中,更新被点击的列表项的选中状态,并更新`ActionBar`的标题或提示信息,展示当前选中的项目数量。 5. **实现`Adapter`的`...

    android listview+checkbox实现多选

    本文将详细介绍如何在Android中使用ListView和Checkbox实现多选功能。 一、ListView概述 ListView是Android提供的一个可以显示大量数据的视图组件,它可以根据需要动态加载数据,通过适配器(Adapter)将数据绑定到...

    popwindow+listview多选

    `ListView`是Android中用来展示大量数据的视图组件,通过复用视图(ViewHolder模式)来提高性能。它可以容纳多种类型的视图,适应不同内容的展示。 在实现多选功能时,我们通常会在`ListView`的每一项中加入`...

    ListView多选操作

    ListView多选操作模式详解CHOICE_MODE_MULTIPLE与CHOICE_MODE_MULTIPLE_MODAL 与该demo配套的文章: http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1105/1906.html

    Android里ListView里面添加CheckBox实现多选

    以上就是实现“Android里ListView里面添加CheckBox实现多选”的核心步骤,结合ViewHolder和ConvertView,可以显著提高列表的滚动性能,同时提供良好的用户体验。在实际项目中,还应考虑其他因素,如异常处理、UI设计...

    Android ListView+checkbox 实现批量删除

    最后,为了提高用户体验,可以考虑使用一个多选模式,例如通过长按条目开启选择模式。这时,我们需要使用ListView的ChoiceMode属性设置为MULTIPLE.choice,这样在长按时会显示选择指示器。同时,我们需要在Adapter中...

Global site tag (gtag.js) - Google Analytics