2013-04-25 25 views
9

Tôi có một ListView với một bộ ArrayAdapter vào nó, và mỗi hàng trong bộ điều hợp chứa bốn nút cần nhận và xử lý các sự kiện bấm. Thông thường trong Android, tôi sẽ gọi SetOnClickListener trên mỗi nút khi tôi tạo ô, nhưng Mono cung cấp khả năng đặt trình xử lý sự kiện cho sự kiện Click thay thế. Có vẻ như có một số điều kì lạ trong Mono, bởi vì tôi gặp phải một trong hai vấn đề phụ thuộc vào nơi tôi đặt trình xử lý sự kiện.Monodroid - Xử lý Nhấp vào các sự kiện bên trong hàng ListAdapter

ArrayAdapter GetView Ví dụ 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)); 
} 

Ở đây, xử lý sự kiện của tôi chỉ được thiết lập một lần cho mỗi nút (tốt!), Nhưng giá trị position là sai hầu hết thời gian. Tôi tự hỏi liệu chuyển đổi từ mã Mono sang Android có đang gây ra GetItem(position) để sử dụng cùng một giá trị cho position mỗi lần (giá trị position được đặt thành khi ô được tạo lần đầu). Mã này sẽ hoạt động hoàn toàn bình thường trên Android.

ArrayAdapter GetView Ví dụ 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)); 

Phương pháp này không gây ra các sự kiện nhấp chuột để bị sa thải cho đúng position, nhưng nó đặt một xử lý sự kiện mới mỗi khi hàng được tái chế. Điều này gây ra các sự kiện nhấp cho nhiều hàng cùng một lúc. Một cách giải quyết cho phương pháp này có vẻ là để giữ cho các tham chiếu đến các trình xử lý sự kiện và loại bỏ chúng trước khi đặt chúng lại bên trong GetView, nhưng điều này có vẻ vô cùng không thích hợp.

Có phương pháp nào tốt hơn để xử lý các sự kiện nhấp trong các mục ListView trong Monodroid không?

+0

Tôi chạy vào cùng một vấn đề. Cách tôi giải quyết nó đã sử dụng mẫu ViewHolder. Bạn luôn có thể đẩy vị trí trong Thẻ cho convertView và kéo nó ra trong trình xử lý sự kiện nhấp chuột. – snowCrabs

Trả lời

0

Tôi cũng gặp sự cố tương tự. Rõ ràng, tôi sẽ tránh giải pháp 2. Hơn nữa, tôi quan sát vấn đề trong giải pháp 1 chỉ xảy ra trên Android 2.3.

Đây là cách tôi khắc phục sự cố.

Tôi giữ tham chiếu đến ListView trong bộ điều hợp, nói _listView. Sau đó, trong phương thức GetItem() của bạn (Đừng bỏ lỡ biến số position. Giá trị của nó là một bí ẩn), hãy gọi _listView.GetPositionForView((View)sender) để có được vị trí chính xác.

+0

Kịch bản tùy chọn 1 đang diễn ra đối với tôi trong tất cả các phiên bản. Tôi đã không thử giải pháp của bạn được nêu ra, nhưng mà chỉ có vẻ như vậy ngược ... không gõ giải pháp của bạn ở tất cả, tôi chỉ muốn nó hoạt động đúng trong Mono để ListView và adapter không cần phải được kết nối chặt chẽ như vậy. – BigFwoosh

+0

Tôi biết, nhưng đây là giải pháp cho vấn đề. Tôi thực sự hy vọng điều này hoạt động đúng trong Mono cho Android là tốt. Ngoài ra, tôi không nghĩ rằng việc giữ một tham chiếu của 'ListView' trong bộ điều hợp được kết hợp chặt chẽ. –

0

Hãy thử với mã này:

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

tôi biết nó là một chủ đề cũ, nhưng nó có rất nhiều phiếu bầu và vẫn đánh dấu là chưa có ai trả

Nó chỉ là hợp lý rằng các kịch bản mà bạn mô tả xảy ra! Nó chẳng liên quan gì đến mono. Nó phải làm với convertview. Đây là những gì tài liệu nói trên chuyển đổi:

convertView - Chế độ xem cũ để sử dụng lại, nếu có thể. Lưu ý: Bạn nên kiểm tra xem chế độ xem này là không rỗng và thuộc loại thích hợp trước khi sử dụng . Nếu không thể chuyển đổi chế độ xem này để hiển thị dữ liệu chính xác , phương pháp này có thể tạo chế độ xem mới.

Ví dụ 1: Trong ví dụ đầu tiên của bạn convertView sẽ được null lần đầu tiên và các sự kiện sẽ được thiết lập.Sau đó, lần tiếp theo phương pháp GetView được gọi là chuyển đổi có thể có hoặc không được rỗng. Nếu nó không phải là null, nó sẽ sử dụng chế độ xem cũ với các sự kiện vẫn được đính kèm! Vì vậy, điều này có nghĩa rằng sự kiện với tham số vị trí vẫn ở chế độ xem trước đó!

Ví dụ 2: Ví dụ này sẽ hoạt động như mong đợi nhưng không hiệu quả như bạn đã đề cập. Nó phải xác định các điều khiển mỗi khi phương thức FindViewById được gọi.

Giải pháp: Giải pháp cho vấn đề hiệu suất này là triển khai mẫu trình xem.

Trước tiên, bạn tạo ra một lớp mà sẽ giữ quan điểm của mình:

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

Bây giờ bạn có thể sử dụng viewholder này trong mã của bạn

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

Để biết thêm thông tin về vấn đề này xem: https://blog.xamarin.com/creating-highly-performant-smooth-scrolling-android-listviews/

Các vấn đề liên quan