xamarin - 带ListView中按钮的CustomAdapter

时间:2018-01-23 07:00:09

标签: c# android listview xamarin

我只使用可点击按钮为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;所以你可以看到我正在谈论的内容。

非常感谢任何帮助:)

1 个答案:

答案 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