Android's ListView reuses rows that have been scrolled out of view. But, that seems to be a problem when handling events on a row's child Views in C#.
An accepted way of adding event handlers in Java is to explicitly set a handler like so:
ImageView img = (ImageView) row.findViewById(R.id.pic);
img.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
System.out.println(position);
}
});
Documents on Xamarin's site encourage developers to use C#'s add event listener pattern which doesn't play nice with reused rows:
ImageView img = row.FindViewById<ImageView> (Resource.Id.pic);
img.Click += (sender, e) => {
Console.WriteLine(position);
};
The Java pattern above which sets an event handler is well suited for row reuse while the C# pattern beneath it which adds an event handler causes handlers to pile up on child Views of the reused rows.
The code below shows my GetView
method from a custom BaseAdapter I wrote.
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;
}
The problem is, when a row is reused, the profilePic
view still has the original "click" handler attached.
Is there a way to (a) wipe out profilePic.Click
or (b) use the Android's profilePic.SetOnClickListener
Java pattern with anonymous functions?
Or, is there a better pattern to use where the "click" handler can still access the proper value of position
?
Or, is there a better pattern to use where the "click" handler can still access the proper value of position?
Use setTag/getTag
method to get right position of clicked row inside Click method of ImageView
click listener:
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);
......
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With