当前位置: 代码迷 >> Android >> android listview 重用view导致的选择混乱有关问题
  详细解决方案

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

热度:84   发布时间:2016-04-28 00:45:54.0
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 stub102                         if (isChecked)103                         {104                             // 添加了该人,button显示删除105                             listFriend.get(index).setReserved01("1");106                         } else107                         {108                             // 删除了该人,button显示添加109                             listFriend.get(index).setReserved01("0");110                         }111                     }112                 });*/113         return convertView;114     }115 116     /**117      * 布局中的元素118      */119     class ViewHolder120     {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()来替代了。

  相关解决方案