Intereting Posts
Верните приложение на передний план Почему имена файлов в выделенной папке не могут содержать специальные символы или начинаться с заглавной буквы? Как скрыть пункт меню на панели действий? Как вы указываете в AndroidManifest.xml, что вы хотите запретить установку на устройствах размером менее 4,7-дюймового устройства? Нужен пример sqlite с Monodroid Открытие файла pdf с сервера с использованием намерений Android TabLayout с viewpager не плавная прокрутка Изменения кода не отражены в .apk Платформа Android: отличия большого размера 800×480 от планшета 1024×600 Как вызвать веб-службу RESTful с Android? Как я могу проверить подписанные данные для In-App Billing Android Market с помощью Java (Servlet) Android: как получить пол и возраст пользователя? «Модернизация» нескольких изображений, прикрепленных по одному многопрофильному запросу Обнаружение использования Google Cast Создание жестких ссылок и Symlinks в Android

Монодроид – обработка событий Click внутри строк ListAdapter

У меня есть ListView с ArrayAdapter, установленным для него, и каждая строка в адаптере содержит четыре кнопки, которые необходимо принимать и обрабатывать события кликов. Обычно в Android я бы назвал SetOnClickListener на каждой кнопке, когда я создаю ячейку, но Mono дает возможность устанавливать обработчики событий для события Click . Похоже, в Mono есть какая-то странность, потому что я столкнулся с одной из двух проблем в зависимости от того, где я устанавливаю обработчик событий.

ArrayAdapter GetView Пример 1:

 View tweetCell = convertView; if (tweetCell == null) { tweetCell = ((LayoutInflater)Context.GetSystemService (Context.LayoutInflaterService)).Inflate (Resource.Layout.TweetCell, null); tweetCell.FindViewById (Resource.Id.btn_moveTweet).Click += (object sender, EventArgs e) => MoveTweet (GetItem(position)); tweetCell.FindViewById (Resource.Id.btn_unfavoriteTweet).Click += (object sender, EventArgs e) => UnfavoriteTweet (GetItem(position)); tweetCell.FindViewById (Resource.Id.btn_hideTweet).Click += (object sender, EventArgs e) => HideTweet (GetItem(position)); tweetCell.FindViewById (Resource.Id.btn_shareTweet).Click += (object sender, EventArgs e) => ShareTweet (GetItem(position)); } 

Здесь мой обработчик событий устанавливается только один раз за кнопку (хорошо!), Но значение position в большинстве случаев неверно. Мне интересно, будет ли преобразование из Mono в код Android приводить к GetItem(position) что GetItem(position) будет использовать одно и то же значение для position каждый раз (значение, для которого position установлена, когда ячейка сначала создана). Этот код будет работать отлично в обычном Android.

ArrayAdapter GetView Пример 2:

 View tweetCell = convertView; if (tweetCell == null) { tweetCell = ((LayoutInflater)Context.GetSystemService (Context.LayoutInflaterService)).Inflate (Resource.Layout.TweetCell, null); } tweetCell.FindViewById (Resource.Id.btn_moveTweet).Click += (object sender, EventArgs e) => MoveTweet (GetItem(position)); tweetCell.FindViewById (Resource.Id.btn_unfavoriteTweet).Click += (object sender, EventArgs e) => UnfavoriteTweet (GetItem(position)); tweetCell.FindViewById (Resource.Id.btn_hideTweet).Click += (object sender, EventArgs e) => HideTweet (GetItem(position)); tweetCell.FindViewById (Resource.Id.btn_shareTweet).Click += (object sender, EventArgs e) => ShareTweet (GetItem(position)); 

Этот метод вызывает срабатывание события click для правильной position , но он устанавливает новый обработчик событий каждый раз, когда строка перерабатывается. Это вызывает события щелчка для большого количества строк одновременно. Обходной путь для этого метода, по-видимому, должен заключаться в том, чтобы сохранять ссылки на обработчики событий и удалять их, прежде чем устанавливать их снова внутри GetView , но это кажется крайне неэлегантным.

Есть ли лучший способ обработки событий кликов внутри элементов ListView в Monodroid?

Solutions Collecting From Web of "Монодроид – обработка событий Click внутри строк ListAdapter"

Я знаю его старый поток, но он имеет много голосов и по-прежнему отмечен как безответный

Логично, что описанные вами сценарии происходят! Это не имеет никакого отношения к моно. Это связано с конвертацией. Это то, что говорит документация об конвертации:

ConvertView – старое представление для повторного использования, если это возможно. Примечание. Перед использованием убедитесь, что это представление не является нулевым и соответствующего типа. Если невозможно преобразовать это представление для отображения правильных данных, этот метод может создать новое представление.

Пример 1: В первом примере convertView будет null в первый раз, и события будут установлены. Тогда, в следующий раз, когда метод GetView будет вызван, convertview может быть или не быть нулевым. Если он не является нулевым, он будет использовать старое представление с включенными событиями! Таким образом, это означает, что событие с параметром позиции остается прежним!

Пример 2: Этот пример будет работать так, как ожидалось, но он не очень эффективен, как вы упомянули. Он должен определять элементы управления каждый раз, когда вызывается метод FindViewById .

Решение . Решение этой проблемы производительности заключается в реализации шаблона зрителя.

Сначала вы создаете класс, который будет содержать ваши представления:

 private class MyViewHolder : Java.Lang.Object { public Button MoveTweet { get; set; } public Button ShareTweet { get; set; } public Button UnfavoriteTweet { get; set; } public Button HideTweet { get; set; } } 

Теперь вы можете использовать этот зритель в своем коде

 public override View GetView (int position, View convertView, ViewGroup parent) { MyViewHolder holder; var view = convertView; if(view != null) holder = view.Tag as MyViewHolder; if (holder == null) { holder = new MyViewHolder (); view = activity.LayoutInflater.Inflate (Resource.Layout.OptimizedItem, null); holder.MoveTweet = view.FindViewById<Button> (Resource.Id. btn_moveTweet); holder.ShareTweet = view.FindViewById<Button> (Resource.Id. btn_shareTweet); holder.UnfavoriteTweet = view.FindViewById<Button> (Resource.Id. btn_unfavoriteTweetTweet); holder.HideTweet = view.FindViewById<Button> (Resource.Id. btn_hideTweet); view.Tag = holder; } holder.MoveTweet.Click += (object sender, EventArgs e) => MoveTweet (GetItem(position)); holder.UnfavoriteTweet.Click += (object sender, EventArgs e) => UnfavoriteTweet (GetItem(position)) holder.HideTweet.Click += (object sender, EventArgs e) => HideTweet (GetItem(position)); holder.FavoriteTweet.Click += (object sender, EventArgs e) => ShareTweet (GetItem(position)); return view; } 

Для получения дополнительной информации об этой проверке: https://blog.xamarin.com/creating-highly-performant-smooth-scrolling-android-listviews/

У меня тоже были проблемы. По-видимому, я избегу решение 2. Более того, я вижу, что проблема в решении 1 произошла только на Android 2.3.

Вот как я исправил проблему.

Я сохраняю ссылку на ListView в адаптере, скажем _listView . Затем, в GetItem() (не пропустите переменную position ее значение – тайна), вызовите _listView.GetPositionForView((View)sender) чтобы получить правильную позицию.

Попробуйте этот код:

  void OnListItemClick(object sender, AdapterView.ItemClickEventArgs e) { var listView = sender as ListView; var item = items[e.Position]; //init your data... tweetCell.FindViewById (Resource.Id.btn_moveTweet).Click += (object sender, EventArgs e) => MoveTweet (item); }