-
-
Save Cheesebaron/9838325 to your computer and use it in GitHub Desktop.
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; | |
} | |
} | |
} | |
} | |
Hi,
we implemented your solution to filter a custom adapter for a listview but the problem is that we are using the SimpleListItemMultipleChoice layout and the checkboxes don't get filtered. Better explained here:
https://forums.xamarin.com/discussion/113722/multichoice-singlechoice-custom-filter-listview
does anybody know how to approach a solution for that? My idea is to get the id or the position of the filtered elements and look in the original list wether they are selected or not and update the results list accordingly but i don't see a way of identifiying the elements.
Thanks for the piece of code, works great.
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>());
Hey, I have implemented sort of same thing on Xamarin Forms with custom adapter renderer on Android and I noticed GetView is called triple times. Position iterated 0 to suggestionList.count then goes back to 0 and iterate three times. Did you notice that by anychance when you tested this on Android?