Monodroid - 处理子事件上的事件重用的ListView行的视图

时间:2015-02-16 03:47:39

标签: c# android mono xamarin xamarin.android

Android的ListView重用已滚出视图的行。 但是,当在C#中处理行的子视图上的事件时,这似乎是一个问题。

在Java中添加事件处理程序的一种可接受的方法是显式设置处理程序,如下所示:

ImageView img = (ImageView) row.findViewById(R.id.pic);
img.setOnClickListener(new View.OnClickListener() {  
    public void onClick(View v) {
        System.out.println(position);
    }  
});

Xamarin网站上的文档鼓励开发人员使用C#的添加事件监听器模式,这种模式对重用行不起作用:

ImageView img = row.FindViewById<ImageView> (Resource.Id.pic);
img.Click += (sender, e) => {
    Console.WriteLine(position);
};

设置事件处理程序之上的Java模式非常适合行重用,而添加事件处理程序下面的C#模式会导致处理程序堆积在子项上重用行的视图。

下面的代码显示了我写的自定义BaseAdapter中的 GetView 方法。

public override Android.Views.View GetView (int position,
                                            View convertView, ViewGroup parent)
{
    View row = convertView;

    //TODO: solve event listener bug. (reused rows retain events).
    if (row == null) {
        row = LayoutInflater.From (userListContext)
                .Inflate (Resource.Layout.UserListUser, null, false);
    }

    ImageView profilePic = row.FindViewById<ImageView> (Resource.Id.profilePic);

    //if(profilePic.Clickable) { /** kill click handlers? **/ }
    profilePic.Click += async (object sender, EventArgs e) => {
        Bundle extras = new Bundle();
        extras.PutString("id", UserList[position].id);

        Intent intent = new Intent(userListContext, typeof(ProfileActivity));
        intent.PutExtras(extras);
        postListContext.StartActivity(intent);
    };

    return row;
}

问题是,当重用一行时,profilePic视图仍然附加了原始的“click”处理程序。

有没有办法(a)消灭profilePic.Click或(b)使用Android的profilePic.SetOnClickListener Java模式和匿名函数?

或者,是否有更好的模式可供“click”处理程序仍能访问position的正确值?

2 个答案:

答案 0 :(得分:3)

  

或者,“click”处理程序可以使用更好的模式   仍然可以访问正确的位置值吗?

使用setTag/getTag方法获取点击行的正确位置点击ImageView点击监听器的方法:

profilePic.SetTag(Resource.Id.profilePic, position);
profilePic.Click += async (object sender, EventArgs e) => {
        int clickedPos = (int)(((Button)sender).GetTag (Resource.Id.profilePic));
        Bundle extras = new Bundle();
        extras.PutString("id", UserList[clickedPos].id);
        ......
};

答案 1 :(得分:1)

ViewHolder模式提及/建议的第一个+1。你正走在正确的轨道上@MicronXD但是我想鼓励你使用ViewHolder模式,它可以很好地利用你行的视图重用。

然后接下来你需要在Activity中创建一个实际上完成另一个Activity的工作的方法,这个新方法应该接受一个int,它是具有你感兴趣的图像的对象的ID,或者你可以传递整个对象。因此,例如,如果要从MainActivity实例化自定义适配器,则可以创建名为public void OnThumbnailClicked(int id)的方法

然后每次单击一个图像时,您将获得被单击的对象的id并像这样调用方法:(我使用过客户示例)

public override View GetView(int position, View convertView, ViewGroup parent)
        {
            CustomerHolder holder = null;
            var view = convertView;

            if (view == null)
            {
                view = Context.LayoutInflater.Inflate(Resource.Layout.CustomRow, null);

                holder = new CustomerHolder();
                holder.Name = view.FindViewById<TextView>(Resource.Id.textViewName);
                holder.Email = view.FindViewById<TextView>(Resource.Id.textViewEmail);
                holder.Phone = view.FindViewById<TextView>(Resource.Id.textViewPhone);
                holder.Image = view.FindViewById<ImageButton>(Resource.Id.imageViewThumbail);

                view.Tag = holder;
            }
            else
            {
                    holder = view.Tag as CustomerHolder;
            }

            //At this point the holder holds reference to your view objects, whether they are 
            //recycled or created new. 
            //Next then you need to populate the views with the Customer info

            var Customer = Customers[position];
            holder.Name.Text = Customer.Name;
            holder.Email.Text = CustomerHolder.Email;
            holder.Phone.Text = Customer.Phone;
            holder.Image.SetImageResource = (Resource.Drawable.defaulthumbnail);
            holder.Image.Clickable = true;
            holder.Image.Click += (o, e) =>
            {
                   var myActivity = (MainActivity)Context;
                   myActivity.OnThumbnailclicked((Customer[position).id);

            };
            return view;
        }

       private class CustomerHolder : Java.Lang.Object
        {
            public TextView Name { get; set; }
            public TextView Email { get; set; }
            public TextView Phone { get; set; }
            public ImageView Thumbnail { get; set; }                
        }        

}