Cuando empecé a trabajar con listas en Android, en casi todos los ejemplos vi que se creaban clases que extendían de BaseAdapter y que estas se creaban para cada Adapter (cuando solo cambiaba la clase y no la plantilla de datos o incluso cuando solo se usaba una sola vez). Así que ante esta particular situación sumado el hecho de los pocos ejemplos de filtrado que encontraba eran con ArrayAdapter y sin usar plantillas personalizadas decidí hacer este post.
Empecemos
Entity.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace CustomListViewAdapter.Models
{
public class Entity
{
public int Id { get; set; }
}
}
User.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace CustomListViewAdapter.Models
{
public class User : Entity
{
public string ListName
{
get { return string.Format("{0} ({1})", Name, Age); }
}
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
}
}
UserDataTemplate.axml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="Text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/UserNameTextView"
android:textColor="#fff" />
<TextView
android:text="Text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/UserAddressTextView"
android:textColor="#aaa" />
</LinearLayout>
ListViewAdapter.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Android.App;
using Android.Views;
using Android.Widget;
using System;
using System.Collections.Generic;
using System.Linq;
namespace CustomListViewAdapter.Adapters
{
public class ListViewAdapter<T> : BaseAdapter<T>, IFilterable
{
protected List<T> Items;
protected List<T> OriginalItems;
private ListViewFilter<T> _listViewfilter;
private int _resource;
private readonly Func<T, View, ViewGroup, View> _viewFunc;
private readonly Func<T, View, View> _simpleViewFunc;
protected Func<List<T>, List<T>> PerformFiltering;
public ListViewAdapter(List<T> items, Func<T, View, ViewGroup, View> getView, Func<List<T>, List<T>> performFiltering = null)
{
this.Items = items;
this._viewFunc = getView;
this.PerformFiltering = performFiltering;
}
public ListViewAdapter(List<T> items, int resource, Func<T, View, View> simpleViewFunc, Func<List<T>, List<T>> performFiltering = null)
{
this.Items = items;
this._resource = resource;
this._simpleViewFunc = simpleViewFunc;
this.PerformFiltering = performFiltering;
}
#region BaseAdapter
public override T this[int position]
{
get { return Items[position]; }
}
public override int Count
{
get { return Items.Count; }
}
public override long GetItemId(int position)
{
var item = Items[position] as Entity;
return null != item ? item.Id : 0;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
if (null != _simpleViewFunc)
return _simpleViewFunc(this.Items[position], convertView ?? LayoutInflater.FromContext(Application.Context).Inflate(_resource, parent, false));
else
return _viewFunc(this.Items[position], convertView, parent);
}
#endregion BaseAdapter
#region Methods
public void Add(T item)
{
if (null != OriginalItems)
this.OriginalItems.Add(item);
else
this.Items.Add(item);
this.NotifyDataSetChanged();
}
public void Remove(T item)
{
if (null != OriginalItems)
this.OriginalItems.Remove(item);
else
this.Items.Remove(item);
this.NotifyDataSetChanged();
}
public void AddRange(IEnumerable<T> items)
{
if (null != OriginalItems)
this.OriginalItems.AddRange(items);
else
this.Items.AddRange(items);
this.NotifyDataSetChanged();
}
#endregion Methods
#region IFilterable
public Filter Filter
{
get
{
if (null == this._listViewfilter)
this._listViewfilter = new ListViewFilter<T>(this);
return this._listViewfilter;
}
}
#endregion IFilterable
private class ListViewFilter<T> : Filter
{
private readonly ListViewAdapter<T> _listViewAdapter;
public ListViewFilter(ListViewAdapter<T> listViewAdapter)
{
this._listViewAdapter = listViewAdapter;
}
protected override Filter.FilterResults PerformFiltering(Java.Lang.ICharSequence constraint)
{
FilterResults results = new FilterResults();
if (null == _listViewAdapter.OriginalItems)
_listViewAdapter.OriginalItems = new List<T>(_listViewAdapter.Items);
var filteringResults = _listViewAdapter.PerformFiltering(_listViewAdapter.OriginalItems);
results.Values = new JavaObject<List<T>>(filteringResults);
results.Count = filteringResults.Count;
return results;
}
protected override void PublishResults(Java.Lang.ICharSequence constraint, Filter.FilterResults results)
{
this._listViewAdapter.Items = ((JavaObject<List<T>>)results.Values).Value;
if (results.Count == 0)
_listViewAdapter.NotifyDataSetInvalidated();
else
_listViewAdapter.NotifyDataSetChanged();
}
}
private class JavaObject<T> : Java.Lang.Object
{
public JavaObject(T obj)
{
this.Value = obj;
}
public T Value { get; private set; }
}
}
}
Main.axml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minWidth="25px"
android:minHeight="25px">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/NameSearchEditText" />
<ListView
android:minWidth="25px"
android:minHeight="25px"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/UsersListView" />
</LinearLayout>
MainActivity.cs -> GetUsers()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private List<User> GetUsers()
{
var random = new Random();
return new List<User>{
new User { Id = 1, Age = random.Next(9,81), Name= "Shoshana L. Robinson", Address= "Ap #691-1861 Fringilla St."},
new User { Id = 2, Age = random.Next(9,81), Name= "Hadassah T. Lawrence", Address = "270-9592 Dui Street"},
new User { Id = 3, Age = random.Next(9,81), Name= "Caleb R. Rios", Address = "375-1704 Feugiat Street"},
new User { Id = 4, Age = random.Next(9,81), Name= "Keaton K. Booth", Address = "Ap #717-1834 Erat. Rd."},
new User { Id = 5, Age = random.Next(9,81), Name= "Laura C. Maynard", Address = "Ap #893-343 Interdum Road"},
new User { Id = 6, Age = random.Next(9,81), Name= "Cailin A. Mcleod", Address = "Ap #484-5309 Augue Road"},
new User { Id = 7, Age = random.Next(9,81), Name= "Chava P. Wallace", Address = "693-5603 Donec St."},
new User { Id = 8, Age = random.Next(9,81), Name= "Isabella I. Bush", Address = "Ap #100-9976 Donec Road"},
new User { Id = 9, Age = random.Next(9,81), Name= "Leah Y. Acevedo", Address = "9389 Pede. Avenue"},
new User { Id = 10, Age = random.Next(9,81), Name= "McKenzie N. Owen", Address = "453-5024 Et Road"},
new User { Id = 11, Age = random.Next(9,81), Name= "Ivor Q. Woodard", Address = "P.O. Box 818, 8492 Eleifend Avenue"},
new User { Id = 12, Age = random.Next(9,81), Name= "Winifred J. Clark", Address = "P.O. Box 760, 2645 Mauris St."},
new User { Id = 13, Age = random.Next(9,81), Name= "Chaney M. Moss", Address = "970-5780 Sagittis Avenue"},
new User { Id = 14, Age = random.Next(9,81), Name= "Justina R. Barr", Address = "P.O. Box 968, 5665 Non, St."},
new User { Id = 15, Age = random.Next(9,81), Name= "Luke E. Orr", Address = "Ap #373-393 Vulputate Street"},
new User { Id = 16, Age = random.Next(9,81), Name= "Thor G. Baxter", Address = "Ap #930-8980 Lacinia St."},
new User { Id = 17, Age = random.Next(9,81), Name= "Moana T. Rodriquez", Address = "Ap #826-8981 Proin St."},
new User { Id = 18, Age = random.Next(9,81), Name= "Aphrodite V. Dominguez", Address = "371-8128 Vulputate Rd."},
new User { Id = 19, Age = random.Next(9,81), Name= "Sade C. Cameron", Address = "8680 Praesent Street"},
new User { Id = 20, Age = random.Next(9,81), Name= "Chaney T. Cooper", Address = "Ap #758-7491 Class St."},
new User { Id = 21, Age = random.Next(9,81), Name= "Lydia W. Cameron", Address = "152-3416 Mi St."},
new User { Id = 22, Age = random.Next(9,81), Name= "Merritt C. Guzman", Address = "Ap #902-2633 Pulvinar Street"},
new User { Id = 23, Age = random.Next(9,81), Name= "Shaeleigh D. Rowland", Address = "851-9396 Praesent Street"},
new User { Id = 24, Age = random.Next(9,81), Name= "Alika Q. Baird", Address = "P.O. Box 982, 6859 Ligula. Av."},
new User { Id = 25, Age = random.Next(9,81), Name= "Bertha M. Burgess", Address = "Ap #297-6268 Aliquam St."},
new User { Id = 26, Age = random.Next(9,81), Name= "Gareth I. Robbins", Address = "468 Taciti St."},
new User { Id = 27, Age = random.Next(9,81), Name= "Hillary H. Johns", Address = "Ap #768-1660 Integer Road"},
new User { Id = 28, Age = random.Next(9,81), Name= "Quincy T. Whitehead", Address = "1325 Vestibulum Rd."}
};
}
Caso 1. Queremos listar usando una única plantilla de datos y sin filtrar
MainActivity.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Activity(Label = "https://reachsos.com", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
var users = GetUsers();
var usersListView = FindViewById<ListView>(Resource.Id.UsersListView);
usersListView.Adapter = new ListViewAdapter<User>(users, Resource.Layout.UserDataTemplate, GetUserView);
}
private View GetUserView(User user, View view)
{
view.FindViewById<TextView>(Resource.Id.UserNameTextView).Text = user.Name;
view.FindViewById<TextView>(Resource.Id.UserAddressTextView).Text = user.Address;
return view;
}
//private List<User> GetUsers()...
}
Caso 2. Queremos listar usando una única plantilla de datos y filtrar
MainActivity.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Activity(Label = "https://reachsos.com", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
var nameSearchEditText = FindViewById<EditText>(Resource.Id.NameSearchEditText);
nameSearchEditText.TextChanged += (s, e) => ((IFilterable)FindViewById<ListView>(Resource.Id.UsersListView).Adapter).Filter.InvokeFilter(string.Empty);
var users = GetUsers();
var usersListView = FindViewById<ListView>(Resource.Id.UsersListView);
usersListView.Adapter = new ListViewAdapter<User>(users, Resource.Layout.UserDataTemplate, GetUserView, GetFilteredUsers);
}
private List<User> GetFilteredUsers(List<User> originalItems)
{
var nameSearchEditText = FindViewById<EditText>(Resource.Id.NameSearchEditText);
if (!string.IsNullOrWhiteSpace(nameSearchEditText.Text))
{
return originalItems.Where(x =>
x.Name.StartsWith(nameSearchEditText.Text, StringComparison.InvariantCultureIgnoreCase) &&
x.Age >= 45).ToList();
}
return originalItems;
}
private View GetUserView(User user, View view)
{
view.FindViewById<TextView>(Resource.Id.UserNameTextView).Text = user.ListName;
view.FindViewById<TextView>(Resource.Id.UserAddressTextView).Text = user.Address;
return view;
}
//private List<User> GetUsers()...
}
Caso 3. Queremos listar usando diferentes plantillas de datos c/s filtrar
OldUserDataTemplate.axml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="Text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/UserNameTextView"
android:textColor="#fb3"
android:textSize="18sp" />
<TextView
android:text="Text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/UserAddressTextView"
android:textColor="#fff" />
<TextView
android:text="Text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/UserBonusTextView"
android:textColor="#aaa" />
</LinearLayout>
MainActivity.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Activity(Label = "https://reachsos.com", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
var nameSearchEditText = FindViewById<EditText>(Resource.Id.NameSearchEditText);
nameSearchEditText.TextChanged += (s, e) => ((IFilterable)FindViewById<ListView>(Resource.Id.UsersListView).Adapter).Filter.InvokeFilter(string.Empty);
var users = GetUsers();
var usersListView = FindViewById<ListView>(Resource.Id.UsersListView);
usersListView.Adapter = new ListViewAdapter<User>(users, GetUserView, GetFilteredUsers);
}
private List<User> GetFilteredUsers(List<User> originalItems)
{
var nameSearchEditText = FindViewById<EditText>(Resource.Id.NameSearchEditText);
if (!string.IsNullOrWhiteSpace(nameSearchEditText.Text))
{
return originalItems.Where(x =>
x.Name.StartsWith(nameSearchEditText.Text, StringComparison.InvariantCultureIgnoreCase) &&
x.Age >= 45).ToList();
}
return originalItems;
}
private View GetUserView(User user, View convertView, ViewGroup parent)
{
View view;
if (user.Age >= 65)
{
view = LayoutInflater.Inflate(Resource.Layout.OldUserDataTemplate, parent, false);
view.FindViewById<TextView>(Resource.Id.UserNameTextView).Text = user.ListName;
view.FindViewById<TextView>(Resource.Id.UserAddressTextView).Text = user.Address;
view.FindViewById<TextView>(Resource.Id.UserBonusTextView).Text = ((user.Age - 65) * 1000).ToString();
}
else
{
view = LayoutInflater.Inflate(Resource.Layout.UserDataTemplate, parent, false);
view.FindViewById<TextView>(Resource.Id.UserNameTextView).Text = user.ListName;
view.FindViewById<TextView>(Resource.Id.UserAddressTextView).Text = user.Address;
}
return view;
}
//private List<User> GetUsers()...
}
No hay comentarios.:
Publicar un comentario