Xamarin,ListView和RecyclerView,单击一个项目,另一个选中

时间:2016-04-10 04:38:04

标签: xamarin android-recyclerview onitemclick

我遇到ListViewRecyclerView

的问题

最初,我创建了一个ListView,一切都很好。然后我为它设置了onClick事件,这样每次点击一个项目时,它都会将颜色变为黄色。我在OnClick中写的MainActivity函数。问题是,当我测试时,不仅该项目改变了颜色而且改变了2个项目。我读到这是因为我重用了视图。

所以我改用我的策略,使用RecyclerView代替,但同样的问题发生。当我单击一个项目以更改其颜色时,下面的另一个项目也会更改。我想这是因为ListViewRecyclerView重用这些项目,所以当我点击一个项目时它们就会混淆。

我不知道如何解决这个问题,我发现一个解决方案是添加一个boolean数组,它标记了哪个项被点击但是不起作用。任何想法的人?

所以这是代码 MainActivity

class MainActivity : Activity
    {
        public RecyclerView recyclerView;
        public RecyclerView.LayoutManager manager;
        public RecyclerView.Adapter adapter;
        List<Row> lst;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);
            init();
            recyclerView = (RecyclerView)FindViewById(Resource.Id.recyclerView);
            manager = new LinearLayoutManager(this);
            recyclerView.SetLayoutManager(manager);
            CustomAdapter adapter = new CustomAdapter(lst, this);
            adapter.ItemClick += onItemClick;
            recyclerView.SetAdapter(adapter);
        }

        public void init()
        {
            lst = new List<Row>();
            for (int i = 0; i < 15; i++)
            {
                Row row = new Row() { field1="1:43:00", field2="09-Apr-16", field3="KPI/Overflow", field4="Kevin Bacon", field5="Unowned", field6= "People Counting @ IPCAM-ID-C-1-1" };
                lst.Add(row);
            }
        }
        public void onItemClick(object sender, int position)
        {
            int itemPos = position + 1;
            //Toast.MakeText(this, "this is " + itemPos, ToastLength.Short).Show();
            recyclerView.GetChildAt(position).SetBackgroundColor(Android.Graphics.Color.Green);
        }
    }

自定义适配器

public class CustomAdapter : RecyclerView.Adapter
    {
        public Activity _activity;
        public List<Row> lst;
        public event EventHandler<int> ItemClick;

        public CustomAdapter(List<Row> lst, Activity activity)
        {
            this.lst = lst;
            this._activity = activity;
        }

        public override int ItemCount
        {
            get
            {
                return lst.Count;
            }
        }

        public void OnClick(int position)
        {
            if (ItemClick!=null)
            {
                ItemClick(this, position);
            }
        }

        public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
        {
            MyViewHolder myholder = holder as MyViewHolder;

            myholder.textView1.Text = lst[position].field1;
            myholder.textView2.Text = lst[position].field2;
            myholder.textView3.Text = lst[position].field3;
            myholder.textView4.Text = lst[position].field4;
            myholder.textView5.Text = lst[position].field5;
            myholder.textView6.Text = lst[position].field6;


        }

        public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
        {
            View v = this._activity.LayoutInflater.Inflate(Resource.Layout.item, parent, false);

            TextView tv1 = (TextView)v.FindViewById(Resource.Id.textView1);
            TextView tv2 = (TextView)v.FindViewById(Resource.Id.textView2);
            TextView tv3 = (TextView)v.FindViewById(Resource.Id.textView3);
            TextView tv4 = (TextView)v.FindViewById(Resource.Id.textView4);
            TextView tv5 = (TextView)v.FindViewById(Resource.Id.textView5);
            TextView tv6 = (TextView)v.FindViewById(Resource.Id.textView6);

            MyViewHolder holder = new MyViewHolder(v, OnClick) { textView1 = tv1, textView2 = tv2, textView3 = tv3, textView4 = tv4, textView5 = tv5, textView6 = tv6 };
            return holder;
        }
    }

    class MyViewHolder : RecyclerView.ViewHolder
    {
        public TextView textView1, textView2, textView3, textView4, textView5, textView6;
        public View mainView;

        public MyViewHolder(View view, Action<int> listener) : base(view)
        {
            mainView = view;
            mainView.Click += (sender, e) => listener(base.Position);
        }
    }

我按照OnClic Xamarin site k处理程序的示例进行操作 https://developer.xamarin.com/guides/android/user_interface/recyclerview/

3 个答案:

答案 0 :(得分:2)

您的问题与您的代码有关。您将正确的位置发送到事件处理程序,然后在Activity中将其递增1。两端应该使用项目位置的从0开始的索引。没有必要增加一个。

要更改所选项目的背景颜色,您可以使用XML格式的选择器,这样您甚至不需要在代码中执行此操作。

这是一个例子。

row_selector.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:color="@android:color/green" />
    <item android:state_selected="false" android:color="@android:color/transparent"/>
</selector>

row_content.axml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/row_layout_parent"
    android:background="@drawable/row_selector">

    <!-- your row content -->

</LinearLayout>

然后您的观看者将更新为此...

class MyViewHolder : RecyclerView.ViewHolder
{
    public TextView textView1, textView2, textView3, textView4, textView5, textView6;
    public View mainView;
    private LinearLayout _layoutParent;

    public MyViewHolder(View view, Action<int> listener) : base(view)
    {
        mainView = view;
        _layoutParent = mainView.FindViewById<LinearLayout>(Resource.Id.row_layout_parent);
        _layoutParent.Click += (sender, e) => _layoutParent.Selected = true;
    }
}

我删除了其他点击事件。如果由于其他原因仍然需要它,那么您可以将其添加回来,但是在选择时仅设置项目背景颜色不是必需的。

答案 1 :(得分:0)

对于Listview,您应该将choiceMode设置如下。

listView.ChoiceMode = ChoiceMode.Single;

希望它可以帮助你:) -

答案 2 :(得分:0)

创建一个可重复使用的 recycleview 适配器 GENERIC

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Support.V7.App;
using Android.Support.V7.Widget;
using Android.Text;
using Android.Text.Style;
using Android.Util;
using Android.Views;
using Android.Widget;
using Java.Util.Zip;
using ActionMenuView = Android.Support.V7.Widget.ActionMenuView;

namespace Android.Basic.Core
{
    public class GenericRecyclerViewAdapter<T> : RecyclerView.Adapter
    {
        /// <summary>
        /// You can set this for different custom cardview
        /// </summary>
        private int CardViewResourceLayout { get; set; }
        public ObservableCollection<T> Items { get; private set; }
        public  event EventHandler<RecyclerViewViewHolder> ItemViewTemplated;
        public RecyclerView.LayoutManager layoutManager;
        public GenericRecyclerViewAdapter(RecyclerView recyclerView, IEnumerable<T> items, int cardViewResourceLayout, bool isList = true, bool isVertical = true) : base()
        {
            
            if(isList)
            {
                var vertical = isVertical ? LinearLayoutManager.Vertical : LinearLayoutManager.Horizontal;
                layoutManager = new LinearLayoutManager(recyclerView.Context, vertical, false);
            }
            else
            {
                var vertical = isVertical ? GridLayoutManager.Vertical : GridLayoutManager.Horizontal;
                layoutManager = new GridLayoutManager(recyclerView.Context, 3, vertical, false);
            }
            recyclerView.SetLayoutManager(layoutManager);
            this.Items = new ObservableCollection<T>(items);
            this.CardViewResourceLayout = cardViewResourceLayout;
            this.Items.CollectionChanged += delegate
            {
                this.NotifyDataSetChanged();
            };
           
        }
        
        public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
        {
            var itemView = LayoutInflater.From(parent.Context).Inflate(CardViewResourceLayout, parent, false);
#if DEBUG
            Log.Info("GenericRecyclerViewAdapter - ", CardViewResourceLayout.ToString());
#endif
            RecyclerViewViewHolder vh = new RecyclerViewViewHolder(itemView);
            return vh;
        }        
        
        public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
        {
            RecyclerViewViewHolder vh = holder as RecyclerViewViewHolder;
            vh.ItemPosition = position;
            vh.TemplateView.Tag = position;
            vh.TemplateView.Click -= TemplateView_Click;
            vh.TemplateView.Click += TemplateView_Click;
            ItemViewTemplated?.Invoke(this, vh);
        }
        public event EventHandler<T> ItemClicked;
     
        private void TemplateView_Click(object sender, EventArgs e)
        {
            var position = (int)((View)sender).Tag;
            this.ItemClicked?.Invoke(sender, this.Items[position]);
          
        }

        public override int ItemCount
        {
            get { return this.Items.Count; }
        }
        public override long GetItemId(int position)
        {
            return base.GetItemId(position);
        }

    }

    public class RecyclerViewViewHolder : RecyclerView.ViewHolder, View.IOnCreateContextMenuListener,
        IMenuItemOnMenuItemClickListener
    {
        public View TemplateView { get; private set; }
        public int ItemPosition { get;  set; }
        public event EventHandler<MenuInfo> ContextMenuCreated;
        public event EventHandler<object> MenuItemClicked;
        public MenuInfo MenuInfo { get; private set; }
        public object Data { get; set; }
        public RecyclerViewViewHolder(View itemView) : base(itemView)
        {
            // Locate and cache view references:
            this.TemplateView = itemView;
            this.TemplateView.SetOnCreateContextMenuListener(this);
           
        }

        public void OnCreateContextMenu(IContextMenu menu, View v, IContextMenuContextMenuInfo menuInfo)
        {
            MenuInfo = new MenuInfo(menu, v, menuInfo);
            ContextMenuCreated?.Invoke(this, MenuInfo);

        }
        private Android.Views.MenuInflater menuInflater = null;
        /// <summary>
        /// After ContextMenuCreated 
        /// </summary>
        /// <param name="resourcemenu"></param>
        public void InflateMenu(int resourcemenu, SpannableString titleColor = null, object dta = null)
        {
            if (dta != null)
                this.Data = dta;
            if (this.TemplateView.Context is AppCompatActivity activity)
            {
                menuInflater = activity.MenuInflater;

            }
            else if (this.TemplateView.Context is Activity activity2)
            {
                menuInflater = activity2.MenuInflater;
            }
            var contextMenu = this.MenuInfo.ContextMenu;
            contextMenu.Clear();
            menuInflater.Inflate(resourcemenu, contextMenu);
            var num = contextMenu.Size() - 1;
            for (int i = 0; i <= num; i++)
            {
                var men = contextMenu.GetItem(i);
                if(titleColor != null)
                {
                    if (i == 0)
                    {                       
                        men.SetTitle(titleColor);
                        men.SetChecked(true);
                    }
                }
                if (i != 0)
                {
                    men.SetOnMenuItemClickListener(this);
                }

            }
        }
        
        public bool OnMenuItemClick(IMenuItem item)
        {
            this.MenuItemClicked?.Invoke(item, this.Data);
            return true;
        }

        public float PosX;
        public float PosY;
        
    }
    
    public class MenuInfo
    {
        public IContextMenu ContextMenu { get; }
        public View View { get; }
        public IContextMenuContextMenuInfo ContextMenuInfo { get; }
        public MenuInfo(IContextMenu contextMenu, View view, IContextMenuContextMenuInfo menuInfo)
        {
            this.ContextMenu = contextMenu;
            this.View = view;
            this.ContextMenuInfo = menuInfo;
        }
    }
}

用法

  RecyclerView recyclerView = new RecyclerView(this);
                    var viewAdapter = new Android.Basic.Core.GenericRecyclerViewAdapter<Java.IO.File>(recyclerView, files, Resource.Layout.directory_item);
                    var indiColor = ThemeHelper.IsDark ? ColorHelper.GetRandomLightColor() : ColorHelper.GetRandomDarkColor();
                    viewAdapter.ItemViewTemplated += (dd, holder) =>
                    {
                        var file = files[holder.ItemPosition];
                        var view = holder.ItemView;
                        var expanded = view.FindViewById<ExpandedView>(Resource.Id.expandedView);
                        expanded.SetToggleColor(indiColor);
                        expanded.SetTitle(file.Name);
                        GenerateRecycler(expanded, file);
                        
                    };
                    recyclerView.SetAdapter(viewAdapter);
                    expandedView.AddExpandedView(recyclerView);