2013-04-25 41 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/

相關問題