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

来源:互联网 发布:域名跳转到淘宝店铺 编辑:程序博客网 时间:2024/05/20 07:51

       没想到,生产一辆跑车,车轮上的螺丝出问题就得花去一定时间。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);}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn this.list.size();}@Overridepublic ArrayList getItem(int position) {// TODO Auto-generated method stubreturn (ArrayList) this.list.get(position);}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic 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的值为2cb.setOnCheckedChangeListener(new OnCheckedChangeListener(){@Overridepublic void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {//保存checked状态到list对应的位置中list.set(pos, isChecked);}});cb.setChecked((Boolean) list.get(pos));//处理radioButtonRadioButton 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;}}


主函数:    

@Overridepublic 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状态为falsefor(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

    


 

原创粉丝点击