Фильтр RecylcerView не работает в xamarin.android - PullRequest
0 голосов
/ 13 сентября 2018

У меня проблемы с фильтрацией данных на панели действий 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 голосов
/ 13 сентября 2018

Я думаю, что вы должны использовать mFilteredLocations в OnBindViewHolder:

if (this.mFilteredLocations.Count > 0)
...
var location = this.mFilteredLocations[position];

, чтобы ваш mLocations оставался вашим исходным списком местоположений, а то, что вы показываете на своем RecyclerView,всегда ваш отфильтрованный список.Очевидно, что в начале и mFilteredLocations, и mLocations должны иметь одинаковые элементы.

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

И в вашем фильтре вы меняете mFilteredLocations и уведомляете, что набор данных изменился, так что все данные обновляются.,Но это вступит в силу только в том случае, если вы сделаете вышеупомянутые изменения.

Здесь у вас есть другой связанный вопрос / ответ, но на Android, если он может послужить вам дополнительным руководством.

Е.И.В.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...