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
的正确值?
答案 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; }
}
}