ListView 中CheckBox与RadioButton的状态解决方法

       没想到,生产一辆跑车,车轮上的螺丝出问题就得花去一定时间。ListView就是这款螺丝,也不知道Android的开发人员是怎么的,这个破ListView竟然折磨了开发人员很久,而且还是在一些基础的控件RadioButton(rb)与CheckBox(cb)的状态使用上,太抓狂,现象如下:

     

       现象一:listview放置rb后onItemClickListener事件失效;

       现象二:listview 放置rb或cb后,用户希望在点击listview中的整条item时,就能变更rb/cb状态,但实际上,用户必须点击到rb/cb后才选中。

       现象三:cb(checkbox) 滚动状态丢失现象: listview 中,如果有10项,其中手机屏幕显示1-6项,其余的7-10项在屏幕中不可见,得向下滚动后才能看到,这个时候,如果选中1、2项,再滚动到7-10项,之后再滚动回来1-6项,就发现1、2项并未被选中。(其现象和asp.net中翻页后丢失item的checkbox状态丢失现象是一样)

       现象四:rb单选功能失效:listview中的单选按钮如果不进行处理,是不可能实现单选功能,而且,现象三的情况也会出现在这里。

      以上这四种现象,哪怕是一种,都足够折磨人的了,现象一、二解决方法如下:
       现象一:在listview 中rb对象XML属性中(cb同理),增加:android:focusable="false"    android:focusableInTouchMode="false",因为rb的焦点是先于listview的,所以,设置屏蔽后,listview事件才能触发

       现象二:修改listview每个条目所需要用的View项对应的xml文件(如rowitem.xml),在LinearLayout对象中,增加: android:descendantFocusability="blocksDescendants" 

<!--现象一、二解决方法-->  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/row_checkbox_item"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:descendantFocusability="blocksDescendants" <!-- 务必设置descendantFocusability项 -->
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/row_checkbox_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <CheckBox
            android:id="@+id/row_checkbox"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="4dp"
            android:layout_marginRight="10dp"
            
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:clickable="false"		<!-- 设置clickable不可选-->
            android:focusable="false"		<!-- 设置foucusable失去焦点-->
            android:focusableInTouchMode="false" /><!-- 设置foucsableInTouchMode失去焦点(点击模式) -->

       <RadioButton
            android:id="@+id/rbtn_phone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:clickable="false"		<!-- 设置clickable不可选-->  
            android:focusable="false"		<!-- 设置foucusable失去焦点 -->
            android:focusableInTouchMode="false"/>	<!-- 设置foucsableInTouchMode失去焦点(点击模式)-->

    </LinearLayout>


       这样,就可以通过修改xml布局文件来初步达到rb和cb的选中和事件触发问题,接下来解决另外两个问题。

     现象三解决办法:

             产生原因:每个item对应一个view,每个view中,可以有rb/cb/txtview等子view控件。listview在滚动时,会重新对每个进入屏幕的item项(view)进行数据载入(可以理解为网页上的翻页,屏幕滚动时,就是翻页),譬如,listview有10条item,,屏幕每次只能显示5条,开始时1-5条显示在屏幕上,另外5条在屏幕外,向下滚动到第7条后,第1-2条item从屏幕消失,第6-7条item显示在屏幕上,此时,listview会重新对6-7条进行数据载入,对于1-2条的item,listview一点也不为他们保留任何状态,所以,现象就产生了。

            另外,滚动屏幕后,譬如,屏幕从1-5条滚动到6-10条,1-5条在屏幕外,第6条在屏幕最顶端,此时如果尝试使用parent.getChildAt(6)访问屏幕顶端的第6条item时,你会发现,会返回null,包括7-10条,都是返回null,但是,getChildAt(0)时却能返回一个对象,原来,系统为了节约资源,会用之前第0项来初始化滚屏后的第6条,而不是重新创建一个item对象(其对应关系一次类推),所以为什么会返回null,就是这个原因,一不留意,极容易产生异常。

            如果对于cb来说,要实现多选 解决办法就是,建立一个List对象,将选中的item对应的状态保存到List中,List下标即是item在listview中的位置position),而值则是cb的状态标志(true/false)。通过重载getview方法实现。代码如下:

使用ArrayAdapter为例子:

public class CustomizedAdapter extends ArrayAdapter<List>{
	static int selectitem=-1; 		//用于记录单选rb的最新选中位置 
	private LayoutInflater inflater;
	private Context context;
	private List list;
	
	public CustomizedAdapter(Context context, List listitem)
	{
		super(context, R.layout.rowcheckoutlist, listitem);
		this.context=context;
		this.list=listitem;
		inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	}
	
	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return this.list.size();
	}

	@Override
	public ArrayList getItem(int position) {
		// TODO Auto-generated method stub
		return (ArrayList) this.list.get(position);
	}

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

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		
		//pos必须声明为final,如果声明成普通类型,那么每次触发cb事件时pos永为0,		
		final int pos  = position;
		View rowView = (View)convertView;
	
		//如果rowView为空时,必须实例化一个xml,	
		if (rowView==null)
		{
			rowView = inflater.inflate(R.layout.rowcheckoutlist, null, true);
		}

		CheckBox cb= (CheckBox) rowView.findViewById(R.id.row_checkbox);
		cb.setTag("tagCheckBox");
		//为每个cb设置监听,当cb状态改变时,保存cb状态到list中,pos是当前listview中cb的位置,
		//譬如,用户点击第二个cb,那么pos的值为2
		cb.setOnCheckedChangeListener(new OnCheckedChangeListener(){
			@Override
			public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
				
				//保存checked状态到list对应的位置中
				list.set(pos, isChecked);	
			}});
		cb.setChecked((Boolean) list.get(pos));

		
		//处理radioButton
		RadioButton rb = (RadioButton) rowView.findViewById(R.id.rbtn_phone);
  		rb.setTag("tabRadioButton");

		//为每个rb设置监听,当前rb选择,保存当前rb对应的pos值到selecteitem(static类型),
		//譬如,用户点击第一个rb,那么selectitem为1,当再点击第二个rb时,
		//selectitem则为2,selectitem永远保存最后单击的rb的位置
  		rb.setOnCheckedChangeListener(new OnCheckedChangeListener(){
   			@Override
  			public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
    				if (isChecked)
    				{
     					selectitem = pos;
    				}
   				}});
  		if (pos == selectitem)
   			rb.setChecked(true);
  		else
   			rb.setChecked(false);

		return rowView;
	}	
}


主函数:    

@Override
public void onCreate(Bundle savedInstanceState)
{
	super.onCreate(savedInstanceState);
	this.setContentView(R.layout.main);
	myListView = (ListView) this.findViewById(R.id.listView1);

	//新建一个List,用于保存cb的状态
	final List listitem = new ArrayList();
	for (int i=0;i<list.size();i++)
  	{
		//初始化list,
   		listitem.add(i,false);
   	}
	CustomizedAdapter adapter = new CustomizedAdapter(this,listitem);
  	myListView.setAdapter(adapter);

	//现象四rb解决方法:
	//设置listview监听事件,该事件主要处理rb的单击时,将屏幕中所有rb状态
	//设置为false,再将当前rb设置成true,完成单选功能
	myListView.setOnItemClickListener(new setOnItemClickListener(){
		@Override
   		public void onItemClick(AdapterView<?> parent, View convertView, int position,long id) 
		{
			//遍历当前Item,设置所有Item的cb状态为false	

			for(int i=0;i<parent.getCount();i++)
    			{
     				View childView = parent.getChildAt(i);
     				if (childView==null) break;
     				RadioButton mRadioButton = (RadioButton) childView.findViewById(R.id.rbtn_phone);
     				mRadioButton.setChecked(false);
    			}			
			//设置选中rb状态为true;
			RadioButton rb = (RadioButton) convertView.findViewById(R.id.rbtn_phone);
			rb.setChecked(true);
		}
	);	
}


 

通过以上方法,彻底解决listview的checkbox和radiobox的单、多选问题。如果有更好方法,欢迎交流

部分参考:http://blog.csdn.net/pathuang68/article/details/6455925

    


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值