Android Monodroid-处理ListAdapter行内的单击事件
我有一个设置了ArrayAdapter的ListView,适配器中的每一行都包含四个按钮,需要接收和处理单击事件。通常在Android中,当我创建单元格时,我会在每个按钮上调用Android Monodroid-处理ListAdapter行内的单击事件,android,android-listview,mono,xamarin.android,xamarin,Android,Android Listview,Mono,Xamarin.android,Xamarin,我有一个设置了ArrayAdapter的ListView,适配器中的每一行都包含四个按钮,需要接收和处理单击事件。通常在Android中,当我创建单元格时,我会在每个按钮上调用SetOnClickListener,但Mono提供了为Click事件设置事件处理程序的功能。在Mono中,这看起来有些奇怪,因为我遇到了两个问题之一,这取决于我在哪里设置事件处理程序 ArrayAdapter GetView示例1: View tweetCell = convertView; if (tweetCell
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));
}
在这里,我的事件处理程序每个按钮只设置一次(很好!),但是位置
值在大多数情况下都是错误的。我想知道从Mono到Android代码的转换是否会导致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事件,但它会在每次循环行时设置一个新的事件处理程序。这会导致多行同时发生单击事件。此方法的一个解决方法似乎是保留对事件处理程序的引用,并在GetView
中再次设置它们之前删除它们,但这似乎非常不雅观
有没有更好的方法来处理Monodroid中ListView项目内的单击事件?我也有类似的问题。显然,我将避免解决方案2。此外,我观察到解决方案1中的问题只发生在Android 2.3上
这就是我解决问题的方法
我在适配器中保留了对列表视图的引用,比如\u ListView
。然后,在您的GetItem()
方法中(不要错过position
变量。它的值是一个谜),调用\u 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);
}
我知道这是一个古老的线索,但它有很多选票,仍然被标记为未答复
您描述的场景发生是合乎逻辑的!这和mono没有任何关系。这与convertview有关。以下是文档在convertview上的说明:
convertView—如果可能,要重用的旧视图。注意:你应该
检查此视图是否为非null,以及是否为适当的类型
使用。如果无法将此视图转换为显示
如果数据正确,此方法可以创建新视图
示例1:
在第一个示例中,convertView第一次将为null,并且将设置事件。然后下次调用GetView方法时,convertview可能为空,也可能不为空。如果它不为null,它将使用旧视图,并且事件仍然附加!因此,这意味着带有position参数的事件仍然来自上一个视图
示例2:
这个示例将按预期工作,但不像您提到的那样效率很高。每次调用FindViewById方法时,它都必须找到控件
解决方案:
此性能问题的解决方案是实现viewholder模式
首先,创建一个将保存视图的类:
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; }
}
现在,您可以在代码中使用此viewholder
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;
}
public override View GetView(int位置、视图转换视图、视图组父视图)
{
我的视窗持有人;
var-view=convertView;
如果(视图!=null)
holder=视图。标记为MyViewHolder;
if(holder==null){
holder=新的MyViewHolder();
视图=activity.LayoutInflater.Inflate(Resource.Layout.OptimizedItem,null);
holder.MoveTweet=view.findviewbyd(Resource.Id.btn_MoveTweet);
holder.ShareTweet=view.FindViewById(Resource.Id.btn\u ShareTweet);
holder.UnfavoriteTweet=view.findviewbyd(Resource.Id.btn_UnfavoriteTweet);
holder.HideTweet=view.findviewbyd(Resource.Id.btn\u HideTweet);
视图.标签=支架;
}
holder.MoveTweet.Click+=(对象发送者,EventArgs e)=>MoveTweet(GetItem(position));
holder.UnfavoriteTweet.Click+=(对象发送者,事件参数e)=>UnfavoriteTweet(GetItem(position))
holder.hideweet.Click+=(对象发送者,事件参数)=>hideweet(GetItem(position));
holder.FavoriteTeet.Click+=(对象发送者,事件参数)=>ShareTweet(GetItem(position));
返回视图;
}
有关此问题的更多信息,请查看:我遇到了相同的问题。我解决这个问题的方法是使用ViewHolder模式。您可以在convertView的标记中插入该位置,然后在click事件处理程序中将其拉出。选项1场景在所有版本中都会发生。我还没有尝试过你的解决方案,但那似乎太落后了。。。我一点也不反对你的解决方案,我只是希望它能在Mono中正常工作,这样ListView和适配器就不需要如此紧密地耦合。我知道,但这就是问题的解决方案。我真的希望这在Android的Mono中也能正常工作。另外,我不认为在适配器中保留ListView
的引用是紧密耦合的。