Monodroid - event processing in child mode. ListView Repeated String Views

Android ListView reuses rows that have been scrolled out of sight. But this seems to be a problem when handling events in a child view of row in C #.

A valid way to add event handlers in Java is to explicitly set the handler as follows:

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

The documents on the Xamarin website encourage developers to use C # to add an event listener template that does not play good results with reusable strings:

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

The Java template above which the event handler sets is well suited for reusing strings, while the C # template below it, which adds an event handler, causes the handlers to be overloaded on the child Types of repeated strings.

The code below shows my GetView method from a custom BaseAdapter that 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 that when you reuse a string in the profilePic , there is still a handler for the original click.

Is there a way (a) to destroy profilePic.Click or (b) to use the Java profilePic.SetOnClickListener Java template with anonymous functions?

Or, is there a better template to use when the click handler can access the correct position value?

+5
source share
2 answers

Or, is there a better template to use where the click handler can still access the correct position value?

Use the setTag/getTag method to get the correct position of the clicked row inside the Click ImageView method to listen for clicks:

 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); ...... }; 
+3
source

First +1 for mention / suggestion of ViewHolder template. You're on the right track @MicronXD, however I want to urge you to use the ViewHolder template, it makes good use of reusing the representations of your rows.

Then you need to create a method in your activity that actually performs the task of starting another Activity, and this new method should take an int, which is the identifier of an object that has an image that interests you, or you can go through the entire object. For example, if you create your own adapter from MainActivity, you can create a public void method OnThumbnailClicked (int id)

Then each time the image is clicked, you get the identifier of the object that was clicked, and you call the method as follows: (I used the client example)

 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; } } } 
+1
source

Source: https://habr.com/ru/post/1213435/


All Articles