c# - Búsqueda a través de RecyclerView-Xamarin.Droid
android xamarin.android (1)
Escribí una demostración simple sobre cómo implementar esta característica, efecto como este . Puedes verlo en este Repositorio de GitHub .
Para obtener más información, puede leer el documento: Filtrar ListView con SearchView en Xamarin. Android y la respuesta de Xaver Kapeller sobre filtrar un RecyclerView
con un SearchView
.
Gracias por la respuesta de Xaver Kapeller, su respuesta sobre Searching Through RecyclerView
fue excelente, por lo que decido traducirla a Xamarin para ayudar a más personas.
- Configurando
SearchView
En la carpeta res/menu
crea un nuevo archivo llamado main.xml
. En él, agregue un elemento y configure actionViewClass
en android.support.v7.widget.SearchView
. Como está utilizando la biblioteca de soporte, debe usar el espacio de nombre de la biblioteca de soporte para establecer el atributo actionViewClass
. Su archivo xml debería verse más o menos así:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_search"
android:title="Search"
android:icon="@android:drawable/ic_menu_search"
app:showAsAction="always|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView" />
</menu>
En su Activity
debe inflar este menú xml como de costumbre, luego puede buscar el MenuItem
que contiene SearchView
y agregar un delegado en QueryTextChange
que vamos a usar para escuchar los cambios al texto ingresado en SearchView
:
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<Android.Support.V7.Widget.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;
}
}
- Configurando el
Adapter
Primero, agregue una clase de modelo que se usará para esta muestra:
public class Chemical
{
public string Name { get; set; }
public int DrawableId { get; set; }
}
Es solo su modelo básico el que mostrará un texto en RecyclerView
. Este es el diseño que muestra el diseño:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">
<ImageView
android:id="@+id/chemImage"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentLeft="true"
android:layout_margin="5dp" />
<TextView
android:id="@+id/chemName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/chemImage"
android:layout_centerInParent="true"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp" />
</RelativeLayout>
Este es el ViewHolder
para la clase ChemicalHolder
:
public class ChemicalHolder : RecyclerView.ViewHolder
{
public ImageView Image { get; private set; }
public TextView Caption { get; private set; }
public ChemicalHolder(View itemView) : base(itemView)
{
Image = itemView.FindViewById<ImageView>(Resource.Id.chemImage);
Caption = itemView.FindViewById<TextView>(Resource.Id.chemName);
}
}
3. Implementando RecyclerView.Adapter
public class RecyclerViewAdapter : RecyclerView.Adapter, IFilterable
{
private List<Chemical> _originalData;
private List<Chemical> _items;
private readonly Activity _context;
public Filter Filter { get; private set; }
public RecyclerViewAdapter(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 RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.Chemical, parent, false);
ChemicalHolder vh = new ChemicalHolder(itemView);
return vh;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
ChemicalHolder vh = holder as ChemicalHolder;
var chemical = _items[position];
vh.Image.SetImageResource(chemical.DrawableId);
vh.Caption.Text = chemical.Name;
}
public override int ItemCount
{
get { return _items.Count; }
}
public class ChemicalHolder{...
private class ChemicalFilter{//Implement the Filter logic
}
Implementando la lógica del filtro
private class ChemicalFilter : Filter { private readonly RecyclerViewAdapter _adapter; public ChemicalFilter(RecyclerViewAdapter 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<Java.Lang.Object>() .Select(r => r.ToNetObject<Chemical>()).ToList(); _adapter.NotifyDataSetChanged(); // Don''t do this and see GREF counts rising constraint.Dispose(); results.Dispose(); } }
Úselo para implementar esta característica
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}, }; _recyclerView = FindViewById<RecyclerView>(Resource.Id.recyclerView); _adapter = new RecyclerViewAdapter(this,chemicals); _LayoutManager = new LinearLayoutManager(this); _recyclerView.SetLayoutManager(_LayoutManager); _recyclerView.SetAdapter(_adapter);//
He estado buscando la forma Xamarin de buscar a través de un recyclerView. ¿Alguien puede referirme amablemente a una demostración sobre cómo hacer eso al estilo Xamarin?