欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android自定义带多选框的listview并避免出现自动选中另外选项

程序员文章站 2022-07-13 23:02:51
...
[align=center][size=x-large][color=red][b]android自定义带多选框的listview[/b][/color][/size][/align]

[align=center][size=medium]先展示下效果图。[/size][/align][align=center][img]http://dl.iteye.com/upload/attachment/0063/7379/607278bb-2d4c-3f73-bd9a-a4d4c830dd6d.jpg[/img][/align]

[size=medium]main.xml[/size]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>

</LinearLayout>


[size=medium]自定义列表显示样式 list_item.xml[/size]
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >

<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_launcher" />

<LinearLayout
android:id="@+id/linearlayout1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/image"
android:orientation="vertical"
>
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="23sp"
android:text="TextView" />

<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
<CheckBox
android:id="@+id/box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
/>

</RelativeLayout>


[size=medium]具体代码如下:[/size]
package org.hwq.list11;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.Toast;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class Main extends Activity {
List<Map<String,String>> data;
ListView lv;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
lv = (ListView) findViewById(R.id.listView1);
data = getData();
// SimpleAdapter a = new SimpleAdapter(this,data, R.layout.list_item,from,to);
// lv.setAdapter(a);
MyAdapter adapter = new MyAdapter(this);
lv.setAdapter(adapter);
}
String[] from = new String[]{
"image","name","info"
};
int[] to = new int[]{
R.id.image,R.id.name,R.id.info
};
int[] img = new int[]{
R.drawable.a,R.drawable.b,R.drawable.c
};
String[] name = new String[]{"诸葛","张飞","关羽","刘备","曹操","曹培","曹仁","董卓","吕布","貂蝉","吕蒙","郭嘉","周瑜"};
public List<Map<String,String>> getData(){
List<Map<String,String>> list = new ArrayList<Map<String,String>>();
for(int i=0;i<13;i++){
Map<String,String> map = new HashMap<String, String>();
map.put("image", ""+img[i%3]);
map.put("name", name[i]);
map.put("info", "信息技术");
list.add(map);
}
return list;
}
public class Holder{
public ImageView image;
public TextView name;
public TextView info;
public CheckBox box;
}
public class MyAdapter extends BaseAdapter{
private LayoutInflater inflater;
public MyAdapter(Context context){
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return data.size();
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}

@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

Holder holder = null;
if(convertView == null){
holder = new Holder();
convertView = inflater.inflate(R.layout.list_item, null);

holder.image = (ImageView) convertView.findViewById(R.id.image);
holder.name = (TextView) convertView.findViewById(R.id.name);
holder.info = (TextView) convertView.findViewById(R.id.info);
holder.box = (CheckBox) convertView.findViewById(R.id.box);
convertView.setTag(holder);
}else{
holder = (Holder) convertView.getTag();
}

holder.image.setImageResource(Integer.parseInt(data.get(position).get("image")));
holder.name.setText(data.get(position).get("name"));
holder.info.setText(data.get(position).get("info"));
holder.box.setId(position);
holder.box.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
CheckBox box = (CheckBox)buttonView;
Toast.makeText(Main.this, "box 位置"+box.getId()+data.get(box.getId()).get("name"), 0).show();
}
});
return convertView;
}

}
}


[size=medium] 下面将对上述代码,做详细的解释,listView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到listView的长度(这也是为什么在开始的第一张图特别的标出列表长度),然后根据这个长度,调用getView()逐一绘制每一行。如果你的getCount()返回值是0的话,列表将不显示同样return 1,就只显示一行。

  系统显示列表时,首先实例化一个适配器(这里将实例化自定义的适配器)。当手动完成适配时,必须手动映射数据,这需要重写getView()方法。系统在绘制列表的每一行的时候将调用此方法。getView()有三个参数,position表示将显示的是第几行,covertView是从布局文件中inflate来的布局。我们用LayoutInflater的方法将定义好的list_item.xml文件提取成View实例用来显示。然后将xml文件中的各个组件实例化(简单的findViewById()方法)。这样便可以将数据对应到各个组件上了。但是按钮为了响应点击事件,需要为它添加点击监听器,这样就能捕获点击事件。至此一个自定义的listView就完成了,现在让我们回过头从新审视这个过程。系统要绘制ListView了,他首先获得要绘制的这个列表的长度,然后开始绘制第一行,怎么绘制呢?调用getView()函数。在这个函数里面首先获得一个View(实际上是一个ViewGroup),然后再实例并设置各个组件,显示之。好了,绘制完这一行了。那 再绘制下一行,直到绘完为止。[/size]

[b][color=red] [size=medium]上面步骤完成后,你会发现,当你点击一个复选框的时候,竟然能看到,有的复选框莫名也自动给点上了。这个很让人郁闷。这其中的问题,本人也搞不明白,希望高手能解答。下面给出解决方案:[/size][/color][/b]

代码:
package org.hwq.listview3;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;


public class Main extends Activity{
//显示数据
private List<Map<String,String>> data =new ArrayList<Map<String,String>>();
private ListView lv;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
init();
lv = (ListView) findViewById(R.id.listview1);
//自定义适配器继承BaseAdapter
MyAdapter adapter = new MyAdapter(this);
lv.setAdapter(adapter);
}
//初始显示数据
private void init() {
for(int i=0;i<20;i++){
Map<String,String> map = new HashMap<String, String>();
map.put("text", "第"+i+"个记录");
data.add(map);
}
}
public class MyAdapter extends BaseAdapter{
LayoutInflater inflater;
//定义CheckBox是否选上的链表,这个很关键
List<Boolean> checked ;
//将要显示的每行View添加到这个map里
Map<Integer,View> map = new HashMap<Integer,View>();
public MyAdapter(Context context) {
inflater = LayoutInflater.from(context);
//初始化checked链表,都置为false,都没选上
checked = new ArrayList<Boolean>();
for(int i=0;i<data.size();i++){
checked.add(false);
}
}
public int getCount() {
//必须返回初始的数据行数,因为ListView要显示多少行,从这里取出
return data.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
//从写getView方法,这个方法是每次ListView要绘制一行记录的时候调用的方法
public View getView(int position, View v1, ViewGroup parent) {
View v;
Holder holder = null;
if(map.get(position) == null){
//如果map中没有这个view记录,依照我们自定义的xml文件生成一个view
v = inflater.inflate(R.layout.list_item, null);
holder = new Holder();
holder.text = (TextView) v.findViewById(R.id.text);
holder.box = (CheckBox) v.findViewById(R.id.box);
map.put(position, v);
final int p = position;
//给CheckBox添加监听器。
holder.box.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
CheckBox b = (CheckBox) v;
//将相应位置的CheckBox的值改变
checked.set(p,b.isChecked());
MyAdapter.this.showData();
}
});
v.setTag(holder);
}else{
v = map.get(position);
holder = (Holder) v.getTag();
}
//说明:CheckBox无法在xml中映射到ListView,所以数据初始化的时候,没有CheckBox
holder.text.setText(data.get(position).get("text"));
holder.box.setChecked(checked.get(position));
return v;
}
protected void showData() {
StringBuffer sb = new StringBuffer();
sb.append("已经选上的记录有:\n");
for(int i=0;i<checked.size();i++){
if(checked.get(i)){
Map<String,String> recode = data.get(i);
sb.append("第").append(i).append("条记录:").append(recode.get("text")).append("\n");
}
}
Toast.makeText(Main.this, sb.toString(), 1).show();
}
}
public final class Holder{
public TextView text;
public CheckBox box;
}
}


[color=darkblue][size=medium]list_item.xml[/size][/color]
[/code]<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >

<TextView
android:id="@+id/text"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textSize="25sp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
/>
<CheckBox
android:id="@+id/box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
/>

</RelativeLayout>
[size=medium]
[color=blue]main.xml[/color][/size]
[code="java"]<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="@+id/listview1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>