• android listview 重用view导致的选择混乱问题


    20150526

    listview是常用的控件,经常用自定义的adapter,为了提高显示效率,常利用view的重用方式防止重绘,但因为重用利用的是旧的view,常导致显示的数据会由于position的位置出现错乱。在一个app项目中我遇到过多次这个问题,包括带Button的都能很好的解决,但今天遇到listview中的item有togglelbutton的情况,绑定的监听器是togglebutton的CompoundButton.OnCheckedChangeListener(),竟然出现了问题,一直没有解决,最后将item的监听换成了View.OnClickListener()才解决问题。

    一般,为了防止数据混乱,会在convertview判断null的if-else之后再获取list里的显示数据。getview的例子如下:

      1     @Override
      2     public View getView(int position, View convertView, ViewGroup parent)
      3     {
      4         // TODO Auto-generated method stub
      5         final ViewHolder holder;
      6         // 优化listview --去掉重用,防止togglebutton的点击位置记录出错 
      7         if(convertView == null)
      8         {
      9             // 使用自定义的布局
     10             holder = new ViewHolder();
     11             convertView = mInflater
     12                     .inflate(R.layout.list_invite_party_member, null);
     13             // 初始化布局中的元素
     14             holder.ivAvatar = (ImageView) convertView.findViewById(R.id.iv_avater);
     15             holder.tvName = (TextView) convertView.findViewById(R.id.tv_name);
     16             holder.tvTag = (TextView) convertView.findViewById(R.id.tv_tag);
     17             holder.btnSelect = (ToggleButton) convertView
     18                     .findViewById(R.id.btn_select);
     19             holder.linearLayout = (LinearLayout) convertView
     20                     .findViewById(R.id.rl_friend_item);
     21             convertView.setTag(holder);
     22         } else
     23         {
     24             holder = (ViewHolder)convertView.getTag();
     25         }
     26         
     27         // 绑定数据
     28         final int index = position;
     29         UserBean bean = listFriend.get(index);
     30         // 设置头像
     31         if (!TextUtils.isEmpty(bean.getUserAvatar()))
     32         {
     33             String avatarUrl = Constant.URL_USER_AVATER + bean.getUserAvatar();
     34             // 初始化异步加载头像对象
     35             finalBitmap = FinalBitmap.create(context);
     36             finalBitmap.configLoadingImage(R.drawable.user_head_02);
     37             finalBitmap.display(holder.ivAvatar, avatarUrl);
     38         } else
     39         {
     40             holder.ivAvatar.setImageResource(R.drawable.user_head_02);
     41         }
     42 
     43         if (!TextUtils.isEmpty(bean.getUserNickname()))
     44         {
     45             holder.tvName.setText(bean.getUserNickname());
     46         } else
     47         {
     48             holder.tvName.setText(bean.getUserPhone());
     49         }
     50         if (!TextUtils.isEmpty(CommonUtils.getUserTags(bean)))
     51         {
     52             holder.tvTag.setText(CommonUtils.getUserTags(bean));
     53             holder.tvTag.setVisibility(View.VISIBLE);
     54         } else
     55         {
     56             holder.tvTag.setVisibility(View.GONE);
     57         }
     58         if (TextUtils.equals(bean.getReserved01(), "1"))
     59         {
     60             // 已添加的场合显示为 删除
     61             holder.btnSelect.setChecked(true);
     62         } else
     63         {
     64             holder.btnSelect.setChecked(false);
     65         }
     66         holder.btnSelect.setOnClickListener(new View.OnClickListener() {
     67             
     68             @Override
     69             public void onClick(View v) {
     70                 // TODO Auto-generated method stub
     71                 ToggleButton view = (ToggleButton)v;
     72                 //boolean isCheckedOld = view.getText().toString().equals("添加")?true:false;
     73                 // 获取最新的点击后check状态
     74                 boolean isChecked = view.isChecked();
     75                 if (isChecked)
     76                 {
     77                     // 添加了该人,button显示删除
     78                     view.setChecked(true);
     79                     listFriend.get(index).setReserved01("1");
     80 
     81                 } else
     82                 {
     83                     // 原来是被选中的,点击后该人被删除
     84                     // 删除了该人,button显示添加
     85                     view.setChecked(false);
     86                     listFriend.get(index).setReserved01("0");
     87                 }
     88             }
     89         });
     90 /*        holder.btnSelect
     91                 .setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
     92                 {
     93 
     94                     @Override
     95                     public void onCheckedChanged(CompoundButton buttonView,
     96                             boolean isChecked)
     97                     {
     98                         
     99                         LogUtil.d("isChecked= " + isChecked );
    100                         LogUtil.d("index= " + index );
    101                         // TODO Auto-generated method stub
    102                         if (isChecked)
    103                         {
    104                             // 添加了该人,button显示删除
    105                             listFriend.get(index).setReserved01("1");
    106                         } else
    107                         {
    108                             // 删除了该人,button显示添加
    109                             listFriend.get(index).setReserved01("0");
    110                         }
    111                     }
    112                 });*/
    113         return convertView;
    114     }
    115 
    116     /**
    117      * 布局中的元素
    118      */
    119     class ViewHolder
    120     {
    121         ImageView ivAvatar;
    122         TextView tvName;
    123         TextView tvTag;
    124         ToggleButton btnSelect;
    125         LinearLayout linearLayout;
    126     }
    View Code


    并且用final的index记住了数据的位置,在下面button监听的动作中就可以获得正确的数据了。

    但是试验发现(注释掉的部分)利用此方法还是不可以,可能是CompoundButton.OnCheckedChangeListener()的问题吧。利用此监听器监听button的动作改变list相应数据会导致位置混乱。只好借用View.OnClickListener()来控制togglebutton的显示了。倒也不算麻烦,本来togglebutton就一般是这两种控制方式。还有要注意的是只要点击的togglebutton,它的check状态就会变,在View.OnClickListener()中也是一样。

    mark一下,所以利用adapter记住btn的状态这件事还是很简单的,就是没有理解到CompoundButton的机制而导致的失败,还好有View.OnClickListener()成功的先例,要不然每个view都绘制list数据很多的话也太不现实了。还有一个checkbox的item没有尝试,不行的话还是要用button或View.OnClickListener()来替代了。

    MissR:stay
  • 相关阅读:
    http
    node 学习 http
    socket.io
    每日日报
    每日日报
    每日日报
    06人件读书笔记之一
    每日日报
    每日日报
    05程序员修炼之道:从小工到专家阅读笔记之三
  • 原文地址:https://www.cnblogs.com/permanent2012moira/p/4531936.html
Copyright © 2020-2023  润新知