RecylcerView过滤器在xamarin.android中不起作用

时间:2018-09-13 10:01:15

标签: android-recyclerview xamarin.android searchview

我无法通过recylerview操作栏过滤searchview中的数据。我有一个项目示例,并尝试实现该方法。但是数据不会过滤。

我将其放在片段上(搜索视图)

 public override void OnCreateOptionsMenu(IMenu menu,MenuInflater menuInflater)
    {
        //SearchMenu
        menuInflater.Inflate(Resource.Menu.nav_search, menu);
        var searchItem = menu.FindItem(Resource.Id.action_search);
        var provider = MenuItemCompat.GetActionView(searchItem);
        mSearchView = provider.JavaCast<Android.Support.V7.Widget.SearchView>();
        mSearchView.QueryTextChange += (s, e) => mLocationsAdapter.Filter.InvokeFilter(e.NewText);
        mSearchView.QueryTextSubmit += (s, e) =>
        {
            Toast.MakeText(this.Activity, "You searched: " + e.Query, ToastLength.Short).Show();
            e.Handled = true;
        };
        MenuItemCompat.SetOnActionExpandListener(searchItem, new SearchViewExpandListener(mLocationsAdapter));
    }

这是我的适配器:

namespace ShopDiaryApp.Adapter
{
    public class LocationsRecycleAdapter : RecyclerView.Adapter,IFilterable
    {
        private readonly Activity mActivity;
        private List<LocationViewModel> mLocations;
        private List<LocationViewModel> mFilteredLocations;
        private int mSelectedPosition = -1;

        public LocationsRecycleAdapter(List<LocationViewModel> locations, Activity activity)
        {
            this.mLocations = locations;
            this.mActivity = activity;
            Filter = new LocationFilter(this);
        }

        public override int ItemCount => this.mLocations.Count;

        public Filter Filter { get; private set; }

        public event EventHandler<int> ItemClick;

        private void OnClick(int position)
        {
            this.ItemClick?.Invoke(this, position);
            NotifyItemChanged(position);
            mSelectedPosition = position;
            NotifyItemChanged(position);
        }

        public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
        {
            if (this.mLocations.Count > 0)
            {
                var vh = holder as ViewHolder;
                if (vh != null)
                {

                    var location = this.mLocations[position];
                    vh.LocationName.Text = location.Name;
                    vh.LocationAddress.Text = location.Address;
                    vh.LocationDescription.Text = location.Description;
                    vh.ItemView.Selected = (mSelectedPosition == position);



                }
            }
        }

        public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
        {
            var v = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.AdapterLocations, parent, false);
            var vh = new ViewHolder(v, this.OnClick);
            return vh;
        }

        public class ViewHolder : RecyclerView.ViewHolder
        {
            public ViewHolder(IntPtr javaReference, JniHandleOwnership transfer)
                : base(javaReference, transfer)
            {
            }

            public ViewHolder(View itemView, Action<int> listener)
                : base(itemView)
            {
                this.LocationName = itemView.FindViewById<TextView>(Resource.Id.textviewLocationsAdapterName);
                this.LocationAddress = itemView.FindViewById<TextView>(Resource.Id.textviewLocationAdapterAddress);
                this.LocationDescription = itemView.FindViewById<TextView>(Resource.Id.textviewLocationAdapterDescription);

                itemView.Click += (sender, e) => listener(this.LayoutPosition);
            }

            public TextView LocationName { get; }
            public TextView LocationAddress { get; }
            public TextView LocationDescription { get; }

        }
        private class LocationFilter : Filter
        {
            private readonly LocationsRecycleAdapter mLocationAdapter;
            public LocationFilter(LocationsRecycleAdapter adapter)
            {
                mLocationAdapter = adapter;
            }

            protected override FilterResults PerformFiltering(ICharSequence constraint)
            {
                var returnObj = new FilterResults();
                var results = new List<LocationViewModel>();
                if (mLocationAdapter.mLocations == null)
                    mLocationAdapter.mLocations = mLocationAdapter.mFilteredLocations;

                if (constraint == null) return returnObj;

                if (mLocationAdapter.mLocations != null && mLocationAdapter.mLocations.Any())
                {
                    // Compare constraint to all names lowercased. 
                    // It they are contained they are added to results.
                    results.AddRange(
                        mLocationAdapter.mLocations.Where(
                            location => location.Name.ToLower().Contains(constraint.ToString())));
                }

                // Nasty piece of .NET to Java wrapping, be careful with this!
                returnObj.Values = FromArray(results.Select(r => r.ToJavaObject()).ToArray());
                returnObj.Count = results.Count;

                constraint.Dispose();

                return returnObj;
            }
            protected override void PublishResults(ICharSequence constraint, FilterResults results)
            {
                using (var values = results.Values)
                    mLocationAdapter.mFilteredLocations = values.ToArray<Java.Lang.Object>()
                        .Select(r => r.ToNetObject<LocationViewModel>()).ToList();

                mLocationAdapter.NotifyDataSetChanged();

                // Don't do this and see GREF counts rising
                //constraint.Dispose();
                //results.Dispose();
            }   
        }
    }
}

protected override void PublishResults(ICharSequence constraint, FilterResults results)中,我得到了过滤后的数据。但是recyler视图不会更新(未过滤)。我错过了什么吗?感谢您的帮助:)

1 个答案:

答案 0 :(得分:1)

我认为您应该在test_shop中使用c('subject','date')

mFilteredLocations

这样您的OnBindViewHolder会保留为原始位置列表,而您在if (this.mFilteredLocations.Count > 0) ... var location = this.mFilteredLocations[position]; 上显示的内容始终是过滤后的列表。 显然,一开始mLocationsRecyclerView必须具有相同的项目。

mFilteredLocations

在过滤器上,您正在更改mLocations,并通知数据集已更改,以便刷新所有数据。但这只有在进行上述更改后才会生效。

Here,您还有另一个相关的问题/答案,但是在Android上,它可以作为进一步的指导。

HIH