Filtrar List View de un listado local y de Internet, Search, Switch Flutter
Te voy a explicar algo que considero muy interesante que es el uso de los filtros para valga la redundancia filtrar datas por aquí en Flutter en este caso tal cual puedes ver obviamente este componente puede estar colocado en cualquier parte y anteriormente si ya has seguido un poquito la aplicación ya tú debes saber que para la parte de los posts que es la que tengo por acá la aquí colocada arriba Lo que pasa que es un poco obvio las pantallas son pequeñas y colocar tanta información en un solo lugar entonces puede parecer es un poco complicado porque a la final otr es la pantalla es pequeña y se pierde un poquito la organización de nuestra aplicación Entonces yo prefería aprovechar características que tenemos aquí en dispositivos móviles que podemos acceder rápidamente a cualquier parte de la aplicación y la coloque por aquí arriba digo por aquí abajo en el botón puede que lo coloque para aquel botón ya que por tema del pulgar creo que es más cómodo por acá pero bueno al menos de momento está aquí tampoco es mucho problema
Entonces qué es lo que tenemos acá Fíjate que aquí tenemos un punto muy importante estos son de los libros que por más que sea yo tengo varios libros pero son contados son creo que alrededor de unos 15 o 30 libros realmente no recuerdo entre español e inglés pero es un número determinado de registros es decir no es como en los posts que tengo 1000 registros por lo tanto a lo que me refiero con todo esto es que va a ser una ordenación local por lo tanto va a ser extremadamente rápida y ahorita te muestro también cómo sería la implementación cuando la ordenación no va a ser local o mejor dicho el filtro no va a ser local entonces por aquí vamos a ver qué fue lo que hice.
Switch con una condición
Fíjate que tengo son los elementos para filtrar los elementos de formulario simplemente un Style con el iconito y todo lo demás esto ya no importa aquí coloco el switch el switch que es para la parte bueno el switch que tenemos acá si lo quiero en español o en inglés aquí fíjate que van cambiando Y esto es porque trabaja exactamente con el mismo valor con el onlyLang Bueno aquí está realmente no tiene mucho sentido la el término porque antes era spanish pero lo fui cortando y ahora estoy viendo que no tiene mucho sentido puede que lo cambie Pero bueno aquí lo que revisamos tanto aquí como acá es el lenguaje que puede ser español o inglés aquí yo creo que sería mejor emplear un enumerado pero otra vez eso es una aplicación chiquita voy a manejar ciertos lenguajes en particulares y obviamente es más cómodo hacerlo mediante un String y más eficiente me ataría decir un poquitico tampoco es gran cosa la diferencia pero lo maneja aquí directamente con un String entonces si está en español que es el valor que obtiene por acá cuando clique as este entonces este se colocaría aquí en español y pasaría a true creo que no tiene mucho misterio otra vez aquí colocamos español cuando lo seleccionamos y colocamos aquí espanish y aquí lo viceversa obviamente esto se va a actualizar automáticamente mediante set State para que cuando presionemos uno ya el otro pierde su valor y podemos hacer este tipo de toggle:
Filtro
Por aquí tal cual puedes ver entonces aquí por cierto Este es el de los post quiero decir es de mi academia porque ahí no tengo el de share solamente el de los lenguajes aquí está y ahí tenemos el toggle y aquí parte de esto También tenemos el precio que funciona de una manera similar ya que para el precio empleo también otro switch tal cual veías con otra variable que en este caso es la de free paid Entonces si es free más o menos lo mismo entonces lo coloco free claro Aquí también estoy colocando de que puede que no seleccione ninguno es decir si yo vengo acá Fíjate que lo puedo Apagar cosa que no sucede aquí pero aquí sí los puedo manejar de manera independiente Pero al final van casados.
Switch con 3 condiciones
Lo que pasa que aquí hay una tercera condición que es pago gratis o simplemente ninguno A diferencia de este que también lo hubiera podido colocar Sí pero bueno a mí me gusta cosas entonces aquí lo estoy manejando de esta forma y es por eso que aquí tenemos un condicional si es free lo que hago es el toggle y lo apago y Bueno si no es free de igual si es vacío o de pago le coloco aquí free porque manejo son solamente tres estados y esto es básicamente lo mismo pero con pay y aquí como te digo con el value colocamos aquí que sea la condición.
Filtro local
La estructura muy sencilla vamos con la parte del filtro como te indicaba viene siendo un listado local por lo tanto es muy sencillo aquí qué fue lo que yo hice básicamente empleo siempre una negación es decir lo veo de al revés por lo tanto aquí lo que pregunto es la condición negada es decir lo que no debería de ocurrir en base al valor y por aquí lo niego es decir si Bueno si esto me deja aquí Lo importante de notar viene siendo siempre la primera condición si esto ol liland es distinto de vacío es decir tiene un valor seleccionado entonces aquí empiezo a comprobar qué es lo que es y aquí este que coloco la condición de negado ya que aquí lo que estoy colocando es cuando no se va a visualizar mientras que si no entra en ninguno de estos filtros Entonces si se visualizara:
SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: StatefulBuilder(
// height: 200,
// color: Colors.white,
builder: (BuildContext context, setState) => Center(
child: Column(
children: [
const SizedBox(
height: 20,
),
Text(LocaleKeys.filters.tr(),
style: Theme.of(context)
.textTheme
.displayMedium!
.copyWith(fontWeight: FontWeight.bold)),
const SizedBox(
height: 10,
),
ListTile(
leading: const Icon(Icons.language,
color: Colors.purple),
title: const Text('Solo en español'),
trailing: Switch.adaptive(
value: _onlyLang == 'spanish',
activeColor: Colors.purple,
onChanged: (value) {
_onlyLang = 'spanish';
_filter();
setState(() {});
}),
),
ListTile(
leading: const Icon(Icons.language,
color: Colors.purple),
title: const Text('Only in english'),
trailing: Switch.adaptive(
value: _onlyLang == 'english',
activeColor: Colors.purple,
onChanged: (value) {
_onlyLang = 'english';
_filter();
setState(() {});
}),
),
ListTile(
leading: const Icon(Icons.exposure_zero,
color: Colors.purple),
title: Text(LocaleKeys.free.tr()),
trailing: Switch.adaptive(
value: _freePay == 'free',
activeColor: Colors.purple,
onChanged: (value) {
if (_freePay == 'free') {
_freePay = '';
} else {
_freePay = 'free';
}
setState(() {});
_filter();
}),
),
ListTile(
leading: const Icon(Icons.payments,
color: Colors.purple),
title: Text(LocaleKeys.pay.tr()),
trailing: Switch.adaptive(
value: _freePay == 'pay',
activeColor: Colors.purple,
onChanged: (value) {
if (_freePay == 'pay') {
_freePay = '';
} else {
_freePay = 'pay';
}
setState(() {});
_filter();
}),
),
Padding(
padding: const EdgeInsets.all(15.0),
child: Container(
height: 1,
color: Theme.of(context).primaryColor),
),
ListTile(
leading:
const Icon(Icons.list, color: Colors.purple),
title: Text(LocaleKeys.categories.tr()),
),
Wrap(
spacing: 1,
alignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.start,
children: categories
.map((c) => TextButton(
child: Text(
c.title,
style: TextStyle(
color: _categoryId == c.id
? Colors.purple
: Theme.of(context)
.colorScheme
.secondary,
fontWeight: _categoryId == c.id
? FontWeight.bold
: FontWeight.w500),
),
onPressed: () {
if (_categoryId == c.id) {
_categoryId = 0;
} else {
_categoryId = c.id;
}
setState(() {});
_filter();
},
))
.toList(),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(LocaleKeys.close.tr()),
),
],
),
),
),
),
);
Mediante show entonces aquí otra vez coloco lo negado y es por eso que aquí ves la negación ya que si no fuera lo negado y sería cuando lo quiero habilitar aquí colocaría el true y aquí colocaría que será Igual igual por lo demás es un poco lo mismo en el resto de los filtros aquí coloco free pay y free Pay es igual igual a free entonces aquí coloco las condiciones en las cuales Él debería de ser en este caso sí le quitamos el negado cuando Debería ser gratis que para mí es cuando le coloco un valor de 0.00 o simplemente no está definido pero por lo comentado niego la condición para indicar cuándo es que se va a ocultar ya que otra vez estamos aquí preguntando por la condición de free para pay es básicamente lo mismo de arriba tal cual puedes ver aquí Bueno muy pendiente aquí con los paréntesis aquí tuve que colocar unos paréntesis por si las moscas pero ahí me funcionó de igual manera y para la categoría exactamente la misma lógica coloco aquí los negados y si no entra en ninguno de estos significa que ese puede mantener Entonces le colocamos un true.
// filters
String _onlyLang = '';
String _freePay = '';
int _categoryId = 0;
Aquí también el truquito aparte de la navegación que yo creo que así queda muy sencillo de entender es que aquí para obviamente Book no tiene una propiedad llamada Show por lo tanto se la tuve que crear específicamente para poder filtrar si reviso acá eh para ver dónde está aquí Se la creé de manera adicional y es precisamente para manejar esa lógica aquí lo coloco Show y por aquí también y en todos los constructores eso fue lo que hizo un pequeño parche ahí y finalmente para filtrar los datos que bueno es lo que estoy manejando actualmente no me ha terminado de convencer Pero bueno por más que sea funciona y tampoco me da tanto problema aquí yo tengo el llamado me fui para el book digo para el de los tutoriales aquí yo tengo el llamado bueno el que habías antes Solo que aquí se llama item Book que es el que me permite crear el elemento es decir la cajita visual que tenemos acá entonces lo que yo hago aquí es si esto no está definido no se va a ver y por lo tanto simplemente dibujo un box del elemento entonces es por eso que podemos ver que aquí se filtran rápidamente por ejemplo Aquí voy a colocar está en inglés si coloco en español Fíjate que desaparece el de inglés pero no es que se elimina del listado sino simplemente lo oculto mediante un show:
Widget _itemBook(int position, BuildContext context) {
final appModel = Provider.of<AppModel>(context, listen: false);
final book = bookResponseModel.books[position];
if (!book.show) {
return const SizedBox();
}
String image = '';
if (book.post.image != '') {
image = '${BlogHelper.baseUrlImage}${book.post.path}/${book.post.image}';
}
return Column(***ITEM)
Tal cual puedes ver y es básicamente Lo bueno aquí no tengo libro gratis es por eso que no aparece nada a la fecha y de pago aparecerían todos que son los que tengo a la fecha y por tecnología un poco lo mismo con javascript ccs python aquí aparecen el resto solamente tengo este en python ya que el resto de los python los coloqué en categorías distintas y es así básicamente como funciona esto como te digo no me termina de convencer mucho Pero recuerda que aquí el tema de los listados con el list builder viene siendo un poco complicado de manejar Entonces tampoco quería simplemente remover elementos del array es decir estar haciendo cada rato el Push y el Pot porque me parece un poco más ineficiente y yo creo que esto sería un poco más eficiente de igual manera puedes comentarlo tú cómo tú solucionarías esta situación algo un poco más elegante pero otra vez al menos de momento es lo que se me ha ocurrido entonces así funciona este esto otra vez viene siendo un listado local y es por eso que ves que todo funciona extremadamente rápido ya la cosa cambia un poquito cuando es un listado que cambia por ejemplo en los post que yo tengo muchísimos post tengo años escribiendo post obviamente no traigo de golpe los 1000 post o más que yo tengo aquí definido sino simplemente voy trayendo los últimos y cuando llega al último entonces va trayendo el resto de las publicaciones tal cual puedes ver llega hasta al final bueno llega y va trayendo más y más aquí llegó al final y está cargando más aquí debería colocar un iconito de carga ya lo colocaré luego recuerde que estoy ahí todavía desarrollando la aplicación pero eso es lo que está haciendo por lo tanto no voy a filtrar sobre lo que tengo local
Filtro remoto o en Internet
Sino sería sobre la totalidad y por lo tanto viene siendo un filtro que realizo es en el servidor por lo tanto aquí otra vez no se llamaría una función local sino sería de manera bueno para el servidor Entonces por lo demás aquí también tengo el Bueno luego te explico lo del botton shic en otro videoo filtros similares aquí sería por un campo de búsqueda pero otra vez eso poco importa Porque se realiza en el servidor y aquí obviamente no tengo nada de pago ni gratis porque son publicaciones completamente abiertas problemas más o menos lo mismo aquí entonces por aquí en el la organización no cambia mucho Aquí Fíjate que ya no estoy llamando una llamada filter sino esto yo lo empleo es como la consulta inicial para obtener mis datos los datos que yo voy a mostrar bueno Esto no le hagas caso Esto es para la siguiente página y demás eso no viene el caso pero aquí puedes ver que voy es preguntando por los filtros el de post o lilan y el de share que son los que yo tengo por acá los filtros que yo tengo por acá definidos estos dos las categorías que están un poquito más abajo aquí está la categoría entonces es más o menos lo mismo pero en este caso estoy llamando a un método de ayuda que yo aquí como:
_dataList() async {
bookResponseModel = await AcademyHelper.getMyBooks(appModel.userToken);
}
Para obtener el listado paginado de los post entonces en pocas palabras lo que está haciendo es a cada rato una petición al servidor para en base a la Selección del usuario simplemente obtener el listado paginado así de simple esa viene siendo la pequeña diferencia lo bueno de esto es que si modularizzar más o menos transparente para ti aquí te muestro un poquito la consulta son simplemente los parámetros y por aquí Bueno hago algunas comprobaciones para definir si si voy a pasar el dato o no Ya que no quiero estar pasando datos vacíos para revisarlos en el servidor si el mismo no está presente aquí entonces no lo anexo como parte de la Data y realizo la petición a mi servidor eso sería prácticamente todo por lo demás aquí finalmente obtengo un listado y al final hago un setState State Bueno aquí tengo otra cosita que las pruebas que estoy haciendo por si está montado hago sec State Pero al final hace un sec State algo sec State y pinta los datos en este caso si estuviera haciendo bueno reescribiendo completamente el listado de publicaciones pero es por lo comentado antes porque tengo muchos posts Entonces no puedo traerlos todos de golpe porque sería extremadamente ineficiente Así que lo Manejo un poco distinto por lo demás este mismo filtro también lo implemente en los tutoriales en la parte de Academia o en los cursos y tiene un funcionamiento similar al de los libros Solo que aquí sería un poquito más simplificado ya que bueno la fecha no estoy hablando en inglés al menos no de manera fluida y por lo tanto no tengo ningún curso hablado en inglés y por lo tanto tampoco tengo un filtro para buscar cursos en inglés pero por lo demás aquí también tengo el listado de categorías y si es gratis o no y aquí si tengo contenido gratis por ejemplo este de YouTube en caso de que no lo veas ahí lo puedes ver que es del curso anterior del Laravel 10 colocar no mentira este es el del est es la versión Live del curso que tengo a la fecha de Laravel el de YouTube está por aquí abajo que creo que tiene el título malo ahora que estoy viendo Pero bueno eso es otro tema así que pues nada así funcionan los filtros cualquier cosa lo puedes comentar y que tú cambiarías de mi implementación y sin más que decir nos vemos en otro video