maher2020
maher2020

Reputation: 61

Filter ListView with SearchView xamarin

I want to filter Listview by Searchview

I use the following Adapter for the filter and it works if I haven't made any new additions to the adapter

When I add a new item to Listview, the search stops completely until I restart the program after adding, modifying or deleting it

full code

adapter class

Upvotes: 0

Views: 270

Answers (1)

Leon Lu
Leon Lu

Reputation: 9224

Do you want to achieve the result like following GIF?

enter image description here

If you want to add the item to the listview, based on your adapter, you should item in the adapter like following code.

   public class TableItemAdapter : BaseAdapter<TableItem>, IFilterable
    {
        public List<TableItem> _originalData;
        public List<TableItem> _items;
        private readonly Activity _context;


        public TableItemAdapter(Activity activity, IEnumerable<TableItem> tableitems)
        {

            _items = tableitems.ToList();
            _context = activity;

            Filter = new TableItemFilter(this);
        }

        //Add data to the `_items`, listview will be updated, if add data in the activity, 
        //there are two different lists, so listview will not update.
        public void AddData(TableItem tableItem)
        {
            _items.Add(tableItem);
            NotifyDataSetChanged();
        }

        public override TableItem this[int position]
        {
            get { return _items[position]; }
        }

        public Filter Filter { get; private set; }

        public override int Count
        {
            get { return _items.Count; }
        }

        public override long GetItemId(int position)
        {
            return position;
        }



        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            var item = _items[position];

            View view = convertView;


            if (view == null) // no view to re-use, create new
                view = convertView ?? _context.LayoutInflater.Inflate(Resource.Layout.TableItem, null);
            //view = _context.LayoutInflater.Inflate(Resource.Layout.TableItem, null);
            view.FindViewById<TextView>(Resource.Id.Text1).Text = item.Heading;
            view.FindViewById<TextView>(Resource.Id.Text2).Text = item.SubHeading;


            return view;

        }
        public override void NotifyDataSetChanged()
        {
           // this.NotifyDataSetChanged();
          base.NotifyDataSetChanged();
        }
    }

    public class TableItemFilter :Filter
    {
        private readonly TableItemAdapter _adapter;
        public TableItemFilter(TableItemAdapter adapter)
        {
            _adapter = adapter;
        }

        protected override FilterResults PerformFiltering(ICharSequence constraint)
        {
            var returnObj = new FilterResults();
            var results = new List<TableItem>();


            if (_adapter._originalData == null)
                _adapter._originalData = _adapter._items;

            if (constraint == null) return returnObj;

            if (_adapter._originalData != null && _adapter._originalData.Any())
            {

                results.AddRange(
                    _adapter._originalData.Where(
                        item => item.SubHeading.ToLower().Contains(constraint.ToString()) | item.Heading.ToLower().Contains(constraint.ToString())));

            }


            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)
                _adapter._items = values.ToArray<Java.Lang.Object>().Select(r => r.ToNetObject<TableItem>()).ToList();

            _adapter.NotifyDataSetChanged();

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

    }

    public  class JavaHolder : Java.Lang.Object
    {
        public readonly object Instance;

        public JavaHolder(object instance)
        {
            Instance = instance;
        }


    }

    public static class ObjectExtensions
    {
        public static TObject ToNetObject<TObject>(this Java.Lang.Object value)
        {
            if (value == null)
                return default(TObject);

            if (!(value is JavaHolder))
                throw new InvalidOperationException("Unable to convert to .NET object. Only Java.Lang.Object created with .ToJavaObject() can be converted.");

            TObject returnVal;
            try { returnVal = (TObject)((JavaHolder)value).Instance; }
            finally { value.Dispose(); }
            return returnVal;
        }

        public static Java.Lang.Object ToJavaObject<TObject>(this TObject value)
        {
            if (Equals(value, default(TObject)) && !typeof(TObject).IsValueType)
                return null;

            var holder = new JavaHolder(value);

            return holder;
        }
    }
}

Then in the activity, you add the data by adapter.

 private void Button1_Click(object sender, System.EventArgs e)
        {

            tableItemAdapter.AddData(new TableItem() { Heading = "test1222", SubHeading = "sub Test" });


        }

Here is my demo, you can download it. https://github.com/851265601/Xamarin.Android_ListviewSelect/blob/master/XAListViewSearchDemo.zip

Upvotes: 1

Related Questions