Skip to content

Instantly share code, notes, and snippets.

@Cheesebaron
Last active March 15, 2023 19:30
Show Gist options
  • Save Cheesebaron/9838325 to your computer and use it in GitHub Desktop.
Save Cheesebaron/9838325 to your computer and use it in GitHub Desktop.
Custom Adapter with Filter
namespace SearchViewSample
{
public class Chemical
{
public string Name { get; set; }
public int DrawableId { get; set; }
}
}
using System.Collections.Generic;
using System.Linq;
using Android.App;
using Android.Views;
using Android.Widget;
using Java.Lang;
using Object = Java.Lang.Object;
namespace SearchViewSample
{
public class ChemicalsAdapter : BaseAdapter<Chemical>, IFilterable
{
private List<Chemical> _originalData;
private List<Chemical> _items;
private readonly Activity _context;
public ChemicalsAdapter(Activity activity, IEnumerable<Chemical> chemicals)
{
_items = chemicals.OrderBy(s => s.Name).ToList();
_context = activity;
Filter = new ChemicalFilter(this);
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var view = convertView ?? _context.LayoutInflater.Inflate(Resource.Layout.Chemical, null);
var chemical = _items[position];
var nameView = view.FindViewById<TextView>(Resource.Id.chemName);
var imageView = view.FindViewById<ImageView>(Resource.Id.chemImage);
nameView.Text = chemical.Name;
imageView.SetImageResource(chemical.DrawableId);
return view;
}
public override int Count
{
get { return _items.Count; }
}
public override Chemical this[int position]
{
get { return _items[position]; }
}
public Filter Filter { get; private set; }
public override void NotifyDataSetChanged()
{
// If you are using cool stuff like sections
// remember to update the indices here!
base.NotifyDataSetChanged();
}
private class ChemicalFilter : Filter
{
private readonly ChemicalsAdapter _adapter;
public ChemicalFilter(ChemicalsAdapter adapter)
{
_adapter = adapter;
}
protected override FilterResults PerformFiltering(ICharSequence constraint)
{
var returnObj = new FilterResults();
var results = new List<Chemical>();
if (_adapter._originalData == null)
_adapter._originalData = _adapter._items;
if (constraint == null) return returnObj;
if (_adapter._originalData != null && _adapter._originalData.Any())
{
// Compare constraint to all names lowercased.
// It they are contained they are added to results.
results.AddRange(
_adapter._originalData.Where(
chemical => chemical.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)
_adapter._items = values.ToArray<Object>()
.Select(r => r.ToNetObject<Chemical>()).ToList();
_adapter.NotifyDataSetChanged();
// Don't do this and see GREF counts rising
constraint.Dispose();
results.Dispose();
}
}
}
}
using System.Collections.Generic;
using Android.App;
using Android.Runtime;
using Android.Support.V4.View;
using Android.Support.V7.App;
using Android.Support.V7.Widget;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace SearchViewSample
{
[Activity(Label = "SearchView Sample", MainLauncher = true, Icon = "@drawable/icon",
Theme = "@style/Theme.AppCompat.Light")]
public class SearchViewActivity : ActionBarActivity
{
private SearchView _searchView;
private ListView _listView;
private ChemicalsAdapter _adapter;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
SupportActionBar.SetDisplayShowHomeEnabled(true);
var chemicals = new List<Chemical>
{
new Chemical {Name = "Niacin", DrawableId = Resource.Drawable.Icon},
new Chemical {Name = "Biotin", DrawableId = Resource.Drawable.Icon},
new Chemical {Name = "Chromichlorid", DrawableId = Resource.Drawable.Icon},
new Chemical {Name = "Natriumselenit", DrawableId = Resource.Drawable.Icon},
new Chemical {Name = "Manganosulfate", DrawableId = Resource.Drawable.Icon},
new Chemical {Name = "Natriummolybdate", DrawableId = Resource.Drawable.Icon},
new Chemical {Name = "Ergocalciferol", DrawableId = Resource.Drawable.Icon},
new Chemical {Name = "Cyanocobalamin", DrawableId = Resource.Drawable.Icon},
};
_listView = FindViewById<ListView>(Resource.Id.listView);
_adapter = new ChemicalsAdapter(this, chemicals);
_listView.Adapter = _adapter;
}
public override bool OnCreateOptionsMenu(IMenu menu)
{
MenuInflater.Inflate(Resource.Menu.main, menu);
var item = menu.FindItem(Resource.Id.action_search);
var searchView = MenuItemCompat.GetActionView(item);
_searchView = searchView.JavaCast<SearchView>();
_searchView.QueryTextChange += (s, e) => _adapter.Filter.InvokeFilter(e.NewText);
_searchView.QueryTextSubmit += (s, e) =>
{
// Handle enter/search button on keyboard here
Toast.MakeText(this, "Searched for: " + e.Query, ToastLength.Short).Show();
e.Handled = true;
};
MenuItemCompat.SetOnActionExpandListener(item, new SearchViewExpandListener(_adapter));
return true;
}
private class SearchViewExpandListener
: Java.Lang.Object, MenuItemCompat.IOnActionExpandListener
{
private readonly IFilterable _adapter;
public SearchViewExpandListener(IFilterable adapter)
{
_adapter = adapter;
}
public bool OnMenuItemActionCollapse(IMenuItem item)
{
_adapter.Filter.InvokeFilter("");
return true;
}
public bool OnMenuItemActionExpand(IMenuItem item)
{
return true;
}
}
}
}
@soupjake
Copy link

If people don't want to use the "nasty object wrapping", you can avoid it if you let your class extend Java.Lang.Object itself like:
public class Chemical : Java.Lang.Object

You'd then change the relevant parts in your FilterResults and PublishResults methods:
returnObj.Values = results.ToArray();

_adapter._items = new List<Chemical>(values.ToArray<Chemical>());

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment