Xamarin BaseExpandableListAdapter按钮点击返回错误View问题
Xamarin可展开购物车列表控件异常问题
我在Xamarin中实现了分组可展开的购物车样式列表,每组子项包含「+1」「-1」按钮和显示数量的EditText控件,目前遇到以下问题:
- 点击「+1」或「-1」按钮时,会更新错误的EditText控件(并非当前点击子项对应的控件)
- 滚动列表后,EditText的值会变为0,且点击按钮时获取到的Holder对象中,
groupPosition和childPosition与实际点击项完全不符(比如点击第2组第2项,却得到groupPosition=0、childPosition=5) - 已为列表设置稳定ID,且所有子项ID唯一,但问题仍未解决
核心实现代码
GetChildView方法
public override View GetChildView(int groupPosition, int childPosition, bool isLastChild, View convertView, ViewGroup parent) { Holder<HolderObject> holder; var child = (JavaObjectWrapper<MobilePOSSubItem>)GetChild(groupPosition, childPosition); if (convertView == null) { convertView = context.LayoutInflater.Inflate(Resource.Layout.mobilePOSTicketsSubItem, null); holder = new Holder<HolderObject>( new HolderObject { GroupPosition = groupPosition, ChildPosition = childPosition, Amount = convertView.FindViewById<EditText>(Resource.Id.etAmount), Tariff = convertView.FindViewById<TextView>(Resource.Id.tariff), Name = convertView.FindViewById<TextView>(Resource.Id.name), Rule = convertView.FindViewById<TextView>(Resource.Id.rule), IconAllotment = convertView.FindViewById<ImageView>(Resource.Id.iconAllotment), AddButton = convertView.FindViewById<ImageButton>(Resource.Id.add), RemoveButton = convertView.FindViewById<ImageButton>(Resource.Id.remove) }); convertView.Tag = holder; convertView.SetTag(Resource.Id.etAmount, holder.Value.Amount); convertView.SetTag(Resource.Id.tariff, holder.Value.Tariff); convertView.SetTag(Resource.Id.name, holder.Value.Name); convertView.SetTag(Resource.Id.rule, holder.Value.Rule); convertView.SetTag(Resource.Id.iconAllotment, holder.Value.IconAllotment); convertView.SetTag(Resource.Id.add, holder.Value.AddButton); convertView.SetTag(Resource.Id.remove, holder.Value.RemoveButton); } else { holder = (Holder<HolderObject>)convertView.Tag; holder.Value.Amount.AfterTextChanged -= EtAmount_TextChanged; } holder.Value.Amount.SetText(child.Object.Value.ToString(), TextView.BufferType.Editable); holder.Value.Amount.SetSelectAllOnFocus(true); holder.Value.Amount.AfterTextChanged += EtAmount_TextChanged; // 省略其他控件赋值代码 }
EtAmount_TextChanged事件处理
private void EtAmount_TextChanged(object sender, AfterTextChangedEventArgs e) { if (sender.GetType().BaseType == typeof(EditText)) { var etAmount = (EditText)sender; var parent = (View) etAmount.Parent.Parent; Holder<HolderObject> holder = (Holder<HolderObject>)parent.Tag; int value = 0; string newValue = e.Editable.ToString(); try { if (!string.IsNullOrEmpty(newValue)) { value = Convert.ToUInt16(newValue); } else { holder.Value.Amount.Text = "0"; } } catch { holder.Value.Amount.Text = "0"; } items[holder.Value.GroupPosition].SubItems[holder.Value.ChildPosition].Value = value; NotifyDataSetChanged(); //UpdateSelectedItem(child, value); } }
OnClick按钮点击处理
public void OnClick(View v) { HideSoftKeyboard(listView); View parent = (View) v.Parent.Parent.Parent; HolderObject holder = ((Holder<HolderObject>)parent.Tag).Value; var child = (JavaObjectWrapper<MobilePOSSubItem>) GetChild(holder.GroupPosition, holder.ChildPosition); if (holder.Amount != null) { int value; if (int.TryParse(holder.Amount.Text, out value)) { if (v.Id.Equals(Resource.Id.add)) { if (value < 299 && (child.Object.ValueMax == null || value < child.Object.ValueMax)) { value++; holder.Amount.Text = value.ToString(); } } else if (v.Id.Equals(Resource.Id.remove)) { if (value > 0 && (child.Object.ValueMin == null || value > child.Object.ValueMin)) { value--; holder.Amount.Text = value.ToString(); } } } else { holder.Amount.Text = "0"; } } else { CultureInfo original = CultureInfo.CurrentCulture; NumberFormatInfo noCurrencySymbol = (NumberFormatInfo)original.NumberFormat.Clone(); noCurrencySymbol.CurrencySymbol = string.Empty; var cbArticle = (CheckBox)v; child.Object.ArticleList.FirstOrDefault(x => x.ArticleId == cbArticle.Id).Value = (cbArticle.Checked) ? 1 : 0; holder.Tariff.Text = string.Format("{0} {1}", child.Object.Currency, child.Object.GetTotalAmount().ToString("C", noCurrencySymbol)); } }
稳定ID设置
public override long GetChildId(int groupPosition, int childPosition) { return (long) items[groupPosition].SubItems[childPosition].Idx; } public override bool HasStableIds { get { return true; } }
预期流程
- 在
GetChildView中,若convertView为null则加载布局,创建包含groupPosition、childPosition及各控件的Holder对象并绑定到convertView的Tag - 为EditText绑定
AfterTextChanged事件,为按钮绑定OnClick事件 - 用户点击「+1」/「-1」按钮→触发
OnClick方法→获取按钮的父View及对应的Holder对象→修改Holder中EditText的值→触发AfterTextChanged事件更新列表子项数据
内容的提问来源于stack exchange,提问作者Fran Turkovic
相关产品推荐
相关产品推荐

