2013-04-25 40 views
9

我有一个ListView,并为其设置了一个ArrayAdapter,并且适配器中的每一行都包含需要接收和处理点击事件的四个按钮。通常在Android中,我会在创建单元格时在每个按钮上调用SetOnClickListener,但是Mono可以为事件Click事件设置事件处理程序。看起来在Mono中有一些奇怪的地方,因为我遇到了两个问题之一,这取决于我设置事件处理程序的位置。Monodroid - 处理ListAdapter行内的Click事件

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值大部分时间是错误的。我想知道从单声道到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)); 

这种方法确实会导致正确的position被解雇的单击事件,但它的每行循环时间设置一个新的事件处理程序。这会导致大量行的点击事件同时发生。此方法的解决方法似乎是保持对事件处理程序的引用,并在将它们再次设置到GetView之前将其删除,但这看起来非常不雅观。

是否有更好的方法来处理Monodroid中的ListView项目内的点击事件?

+0

我遇到了同样的问题。我解决它的方式是使用ViewHolder模式。您可以随时在convertView的标签中推入位置,并在click事件处理程序中将其拉出。 – snowCrabs 2013-04-26 15:48:30

回答

0

我也有类似的问题。显然,我会避免解决方案2.此外,我观察到解决方案1中的问题只发生在Android 2.3上。

这是我如何解决这个问题。

我在适配器中保留对ListView的引用,如_listView。然后,在你的GetItem()方法中(不要错过position变量,它的值是一个谜),请拨打_listView.GetPositionForView((View)sender)以获得正确的位置。

+0

在所有版本中,选项1的情况正在发生。我还没有尝试过你的解决办法,但只是似乎如此倒退...不敲你的解决方案在所有的,我只是希望它在单工作正常,这样的ListView和适配器没必要如此紧密耦合。 – BigFwoosh 2013-04-29 13:10:46

+0

我知道,但这是解决问题的办法。我确实希望这适用于Android的Mono。另外,我不认为在适配器中保留“ListView”的引用是紧密耦合的。 – 2013-04-29 18:07:14

0

尝试使用此代码:

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); 
    } 
1

我知道它的一个古老的线程,但它有很多票,并且仍被标记为解答

这是合乎逻辑的一些情形中你描述的发生!它与单声道无关。它与convertview有关。这是文档在convertview上所说的内容:

convertView - 如果可能,重新使用旧视图。注意:您应该在 使用前检查此视图是否为非空以及适当类型。如果无法将此视图转换为显示 正确的数据,则此方法可以创建新视图。

例1: 在你的第一个例子中,convertView将为空在第一时间和事件将被设置。然后在下一次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; 
} 

使用viewholder欲了解更多相关信息,请上网:https://blog.xamarin.com/creating-highly-performant-smooth-scrolling-android-listviews/

相关问题