为什么Xamarin.Android RecyclerView.Adapter不通用?

时间:2017-11-19 12:16:22

标签: xamarin android-recyclerview xamarin.android

我注意到RecyclerView.Adapter中的Xamarin.Android类型不是通用的。为什么会这样?根据{{​​3}},它似乎在原生Android中被定义为通用的。这有什么潜在的原因吗?或者它是某种向后兼容的场景?

2 个答案:

答案 0 :(得分:0)

您可以在C#中创建通用的RecycleView,但不能在Java中创建。在Java中,您需要多次编写代码。这就是为什么Java android即使是简单的事件处理程序也更糟糕的原因,由于Java的本质,Android Team Engineers懒于实现所有数据事件处理。

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

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Support.V7.Widget;
using Android.Util;
using Android.Views;
using Android.Widget;

namespace XamarinAndroid.Basic.Core
{
    public class GenericRecyclerViewAdapter<T> : RecyclerView.Adapter
    {
        /// <summary>
        /// You can set this for different custom cardview
        /// </summary>
        public int CardViewResourceLayout { get; set; }
        public ObservableCollection<T> Items { get; private set; }
        public event EventHandler<RecyclerViewViewHolder> ItemViewTemplated;
        public GenericRecyclerViewAdapter(IEnumerable<T> items, int cardViewResourceLayout) : base()
        {
            this.Items = new ObservableCollection<T>(items);
            this.CardViewResourceLayout = cardViewResourceLayout;
            this.Items.CollectionChanged += (sender, e) =>
            {
                try
                {
                    this.NotifyDataSetChanged();
                }
                catch { }
            };

        }

        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;
            this.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(this, 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
    {
        public View TemplateView { get; private set; }
        public int ItemPosition { get;  set; }

        public RecyclerViewViewHolder(View itemView) : base(itemView)
        {
            // Locate and cache view references:
            this.TemplateView = itemView;
        }
    }
}

向每个视图分配数据

var recyclerViewToday = this.FindViewById<Android.Support.V7.Widget.RecyclerView>(Resource.Id.recyclerViewToday);
            var layoutManager = new LinearLayoutManager(this);
            recyclerViewToday.SetLayoutManager(layoutManager);
            var  adapter = new GenericRecyclerViewAdapter<FavoriteModel>(previousList, Resource.Layout.recent_list_item);
            adapter.ItemViewTemplated += (d, holder) =>
            {
                var indicate = holder.ItemView.FindViewById<View>(Resource.Id.indicatorItemmRec);
                indicate.SetBackgroundColor(ColorHelper.GetRandomLightColor());

                (holder.ItemView.FindViewById<TextView>(Resource.Id.wordTxtRec)).Text = adapter.Items[holder.ItemPosition].Word;

                var textView = (holder.ItemView.FindViewById<TextView>(Resource.Id.definitionTxtRec));
                if (!string.IsNullOrEmpty(previousList[holder.ItemPosition].Definition))
                    textView.Text = previousList[holder.ItemPosition].Definition;
                else
                    textView.Visibility = Android.Views.ViewStates.Gone;
            };
            recyclerViewToday.SetAdapter(adapter);

结果 enter image description here

答案 1 :(得分:0)

干净、通用且可重复使用

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 = context.FindViewById<RecyclerView>(Resource.Id.recycler);
            var viewAdapter = new Android.Basic.Core.GenericRecyclerViewAdapter<StorageFile>(recyclerView, files, Resource.Layout.main_item);
            viewAdapter.ItemViewTemplated += (dd, holder) =>
            {
                //CardView
                CardView cardView = holder.ItemView.FindViewById<CardView>(Resource.Id.CategorycardView);
                cardView.SetCardBackgroundColor(ThemeHelper.IsDark ? Color.ParseColor("#303030") : Color.White);
                var indicator = holder.ItemView.FindViewById<LinearLayout>(Resource.Id.indicator);
                indicator.SetBackgroundColor(ThemeHelper.IsDark ? ColorHelper.GetRandomLightColor() : ColorHelper.GetRandomDarkColor());
                var file = files[holder.ItemPosition];
                var itemIcon = holder.ItemView.FindViewById<ImageView>(Resource.Id.itemIcon);
                var icon = file.GetFileThumbnail();
                if (icon != null)
                {
                    itemIcon.SetImageBitmap(icon);
                }
                TextView itemName = holder.ItemView.FindViewById<TextView>(Resource.Id.itemName);
                itemName.Text = file.DisplayName;
                itemName.SetTextColor(textColor);

               
            };
            viewAdapter.ItemClicked += (dd, ff) =>
            {
                var checkBttn = (dd as View).FindViewById<ImageButton>(Resource.Id.check_boxBttn);
                
               
            };
            recyclerView.SetAdapter(viewAdapter);