我只使用可点击按钮为CustomAdapter
做了简单ListView
。
这是我的适配器,按下按钮将toast
项目位置:
public class ViewHolder : Java.Lang.Object
{
public TextView txtName { get; set; }
public TextView txtAge { get; set; }
public TextView txtEmail { get; set; }
public Button button1 { get; set; }
}
public class CustomAdapter : BaseAdapter
{
private Activity activity;
private List<Person> persons;
public CustomAdapter(Activity activity,List<Person> persons)
{
this.activity = activity;
this.persons = persons;
}
public override int Count
{
get
{
return persons.Count;
}
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return persons[position].Id;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var view = convertView;
if (view == null)
{
view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.list_view_dataTemplate, parent, false);
var txtName = view.FindViewById<TextView>(Resource.Id.textView1);
var txtAge = view.FindViewById<TextView>(Resource.Id.textView2);
var txtEmail = view.FindViewById<TextView>(Resource.Id.textView3);
var button1 = view.FindViewById<Button>(Resource.Id.button1);
view.Tag = new ViewHolder() { txtName = txtName, txtAge = txtAge, txtEmail = txtEmail, button1 = button1 };
}
var holder = (ViewHolder)view.Tag;
holder.txtName.Text = "name " + position;
holder.txtAge.Text = "age " + position;
holder.txtEmail.Text = "email " + position;
holder.button1.Click += delegate
{
Toast.MakeText(Application.Context, "pos: " + position.ToString(), ToastLength.Short).Show();
};
return view;
}
我的问题是,当我点击此按钮一次时,我会逐一获得Toasts
个。与"pos: 1" => "pos: 2" => "pos: 3" => "pos: 0"
类似。对于不同的行,Toast
消息以不同的方式弹出。
我正在努力解决这个问题几个小时,我无法找到解决这个问题的方法。
我已经制作了一个Github repo以及整个&#34;测试项目&#34;所以你可以看到我正在谈论的内容。
非常感谢任何帮助:)
答案 0 :(得分:2)
问题是由Android中的视图回收功能引起的。
您正在检查convertView
是否为空,这是正确的,但是当它不为空时,您正在设置其属性,包括Click
事件处理程序。
问题是,当您使用+=
时,新事件处理程序添加到已存在的,因此当视图多次循环使用时,该按钮可能附加了几个事件处理程序,这会导致出现几个Toast消息。
要解决此问题,您应该只在初始view
创建中添加事件处理程序:
public override View GetView(int position, View convertView, ViewGroup parent)
{
var view = convertView;
if (view == null)
{
view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.list_view_dataTemplate, parent, false);
var txtName = view.FindViewById<TextView>(Resource.Id.textView1);
var txtAge = view.FindViewById<TextView>(Resource.Id.textView2);
var txtEmail = view.FindViewById<TextView>(Resource.Id.textView3);
var button1 = view.FindViewById<Button>(Resource.Id.button1);
view.Tag = new ViewHolder() { txtName = txtName, txtAge = txtAge, txtEmail = txtEmail, button1 = button1 };
button1.Tag = position;
button1.Click += (sender, args) => {
Toast.MakeText(Application.Context, "pos: " + ((Button)sender).Tag.ToString(), ToastLength.Short).Show();
};
}
var holder = (ViewHolder)view.Tag;
holder.txtName.Text = "name " + position;
holder.txtAge.Text = "age " + position;
holder.txtEmail.Text = "email " + position;
holder.button1.Tag = position;
return view;
}
请注意,我将position
设置为button
的标记。我最初直接在事件处理程序中使用了position
变量,但不幸的是,这不起作用,因为当在处理程序中使用变量时,它被提升并始终引用原始position
视图创建时。使用sender
的{{1}},您始终可以按预期检索当前值。
作为 @pskink 建议的简化,您可以向Tag
添加position
属性和ShowToast
方法。然后你可以直接在ViewHolder
处理程序中使用ViewHolder
,代码会简单得多:
更新了Click
:
ViewHolder
并更新public class ViewHolder : Java.Lang.Object
{
public TextView txtName { get; set; }
public TextView txtAge { get; set; }
public TextView txtEmail { get; set; }
public Button button1 { get; set; }
public int position { get; set; }
public void ShowToast()
{
Toast.MakeText(Application.Context, "pos: " + position.ToString(), ToastLength.Short).Show();
}
}
:
GetView