Chip y ChipGroup
Explicación de los conceptos de Chip y ChipGroup.
DEFINICIÓN
Chip
Hereda de:
Los chips son elementos compactos que representan un atributo, texto, entidad o acción. Permiten al usuario introducir información, seleccionar una opción, filtrar contenido o ejecutar una acción.
El widget Chip
es un wrapper sobre la clase ChipDrawable
que contiene además de dicha clase, todo lo que afecta al layout y la lógica para soportar diferentes formas de interacción (tactil, ratón, teclado, accesibilidad...).
El Chip y el icono de cerrar son considerados Views separadas y contienen su propio comportamiento y estado.
ChipGroup
Hereda de ViewGroup
.
Un ChipGroup
es utilizado para acoger múltiples Chips.
USO DESDE XML
Como hemos visto, un ChipGroup
contiene varios Chips
. Por este motivo, podemos crear un ChipGroup
de la siguiente manera:
Estos chips son clicables y tienen una animación cuando son pulsados, pero no tienen lógica asignada.
ATRIBUTOS CHIP
Todos los atributos de la clase Chip estan soportados. Sin embargo, hay que evitar utilizar algunos atributos heredados ya que se van a ignorar. Esto se debe a que los Chips gestionan estas funcionalidades con otros atributos específicos.
Los atributos heredados que no se deben usar son:
android:background
android:drawableStart
android:drawableEnd
A continuación se van a presentar los atributos básicos de la clase Chip
:
android:chipBackgroundColor
Permite cambiar el color de fondo del Chip.
android:chipStrokeColor
Permite definir el color del contorno del Chip.
android:chipStrokeWidth
Permite definir el ancho del contorno del Chip.
android:checkable
Si esta seteado en True, el chip puede ser cambiado de estado, en caso contrario, el chip funcionará como un botón.
android:text
Es un atributo obligatorio y expresa el texto que se va a mostrar al usuario.
A partir del siguiente atributo cambiamos el contexto a App
.
app:chipIcon
Expresa un icono que se coloca a la izquierda del Chip.
app:checkedIcon
Expresa un icono que muestra si el Chip
ha sido activado. Normalmente en la izquierda.
app:closeIcon
Expresa un icono personalizado para cerrar el Chip
.
ATRIBUTOS CHIPGROUP
app:singleLine
Las Chips se van acomodando en varias lineas por defecto. Sin embargo, a veces puede ser util acomodarlas en una sola linea y combinar esto con un HorizontalScollView
.
app:singleSelection
Permite limitar las Chips activadas en un ChipGroup
a solo una.
De esta manera se puede imitar el comportamiento de un RadioGroup
en el cual cuando un RadioButton
es marcado, el resto se desmarcan.
Cuando se añade un Chip a un ChipGroup, su estado se preserva. Si el ChipGroup es de selección única y ya hay un Chip seleccionado, cuando introduzcamos un Chip seleccionado, el anterior se deseleccionará.
PERSONALIZACIÓN
En este apartado vamos a añadir otro elemento muy util para la personalización de elementos visuales, esto son los estilos:
Styles
Un recurso de estilo define el formato y el aspecto de una IU. Se puede aplicar un estilo a una View
individual (desde dentro de un archivo de diseño), a una Activity
completa o una aplicación (desde dentro del archivo de manifiesto).
En nuestra App tenemos el archivo themes.xml
que es el que nos da el estilo del tema "light" y tenemos otro que es themes.xml (night)
que el que nos da el tema "oscuro".
En estos archivos se programan los estilos de los elementos visuales que cambian en función del tema.
Sin embargo, en nuestra App, los Chips no van a cambiar de estilos en función del tema, por eso vamos a crear un archivo de Resources llamado styles.xml
donde van a ir almacenados los estilos que no varían en función del tema.
styles.xml
Como se puede ver, al definir un estilo para los Chips, tenemos que definir un parent, en este caso es Widget.MaterialComponents.Chip.Entry
aunque en función de a qué le queramos definir el estilo le pondremos un parent u otro.
Definir el style
Una vez que hemos creado el estilo, hay que definirlo para los diferentes Chips que queremos que lo tengan.
En este caso vamos a hacer que los Chips alternen, uno con estilo con otro predefinido para que se vea la diferencia:
Si se fijan, en ningún sitio se ha hecho referencia al atributo android:closeIcon y sin embargo los que tienen estilo lo traen incorporado. Esto se debe a que el parent Widget.MaterialComponents.Chip.Entry
incluye este closeIcon
predefinido en su código.
De la misma manera trae un checkedIcon
predefinido que se muestra en la siguiente captura:
Sin embargo, como hemos dicho antes, al no contener la lógica, el closeIcon no tiene la capacidad de cerrar el Chip todavía.
chipIcon
Tambien podemos personalizar los Chips para que se muestren iconos al inicio de los Chips, de esta manera mejoramos la experiencia de usuario permitiendo que con un golpe de vista se sepa a que hacemos referencia:
Listas de estados
En la página de los Button, vimos ya este término pero no lo pudimos aplicar completamente ya que el Button solo tiene un estado.
Recordamos
Un StateListDrawable
es un objeto de diseño definido en XML que usa varias imágenes distintas para representar el mismo gráfico, según el estado del objeto.
Por ejemplo, un widget Button
puede estar en varios estados (presionado, en foco o ninguno de estos) y, mediante un elemento de diseño de lista de estados, puedes cambiar la imagen de fondo para cada estado.
Puede describir la lista de estados en un archivo en formato XML. Cada gráfico se representa a través de un elemento <item>
dentro de un solo elemento <selector>
. Cada <item>
usa varios atributos para describir el estado en que debería usarse como gráfico del elemento de diseño.
Durante cada cambio de estado, se recorre de arriba abajo la lista de estados, y se utiliza el primer elemento que coincida con el estado actual; la selección no depende de la "mejor coincidencia", sino del primer elemento que cumple con los criterios mínimos del estado.
Aplicamos
En el caso de los Chip, tenemos dos estados, cuando el Chip se encuentra en estado Checked
y cuando se encuentra en el estado unChecked
.
A continuación vamos a utilizar un StateListDrawable para definir un cambio de color en el texto en función del estado del Chip.
Para ello tenemos que crear un Resource
que llamaremos ch_textcolor.xml
y contendrá un selector
con dos items
, uno que se ejecutará en el estado Checked
y otro que se ejecutará en el estado unChecked
:
Para aplicar esto a los chips, simplemente llamamos al drawable llamado ch_textcolor
en el atributo android:textColor
:
PROGRAMAR EVENTOS DESDE CÓDIGO
Hacer referencia a todos los Chips
En el caso de los Chips
, al estar todos en el mismo ChipGroup
, podemos hacer referencia a todos ellos sin utilizar los ids personales sino un bucle for que recorra todos los items que contiene dicho ChipGroup
.
Para ello lo que si que necesito es dar un id al ChipGroup:
Ahora en el archivo MainActivity.kt podemos programar dicho bucle:
IMPORTANTE
Cuando hacemos referencia a los hijos del ChipGroup
, estos son referenciados como objetos de tipo View!
(por diseño de la clase).
Es por ese motivo que es fundamental crear una variable sin inicializar de tipo Chip
a la que darle el valor de cada uno de los hijos y castearla al tipo Chip
.
Esto lo vemos en la línea 17 del código.
setOnCloseIconClickListener
Hasta este momento, no hemos podido utilizar el botón de cerrar en los Chips ya que este no tenía la lógica implementada, eso cambia con el siguiente código:
Son nuevas las lineas 19 y 20.
Desde este momento, tenemos un listener en todos los Chips a la espera de que pulsemos el botón de cerrar para eliminar la View.
setOnClickListener
También, como en todos los botones, podemos generar código que se ejecute al pulsar el Chip en sí. Para ello vamos a implementar el siguiente código:
IMPORTANTE
Igual que ocurría con los hijos del ChipGroup
, cuando utilizo un condicional if, la variable it
hace referencia a un objeto de clase View!
.
Los objetos View!
no tienen atributo text
y por lo tanto me daría error intentar acceder al text de it.
Es por ese motivo que tenemos que realizar un cast a Chip que si que tienen el atributo text.
Añadir Chips desde código
A continuación vamos a añadir un Chip desde código. Los datos son fijos por que aún no sabemos interaccionar con el usuario pero podrían ser Tags de búsqueda que marque el usuario en un EditText por ejemplo:
IMPORTANTE
En este caso en las líneas 44 y 46 vemos que tambien es necesario realizar casting para cumplir con las necesidades de tipos ya que el método addView(View!)
solo permite parametros de tipo View y el método removeView()
, al estar en un ChipGroup, tiene que recibir un Chip.
Modificar estilo de nuevos Chips
Como hemos visto, se pueden crear Chips desde código, sin embargo, no existe una API que permita cambiar el estilo de este Chip.
Por ese motivo, AirBNB que es una de las empresas que más soluciones desarrolla para Android ha creado una biblioteca pensada para modificar el estilo de manera programática.
Dejo un enlace por si les interesa:
Last updated