Tabs más familiares a tus usuarios en Xamarin.Forms
Entre la gran variedad de páginas pre-cargadas que nos ofrece Xamarin.Forms tenemos la opción de elegir la TabbedPage
que en realidad no es más que un contenedor de otras páginas y que las hace accesibles a través de tabs. Seguramente la has usado y piensas que es genial, lo que no es tan genial es que es un poco… estática y no permite mucha personalización.
Es por eso que decidí crear un custom renderer que permita darle un poco más de estilo, haciendo que se vea más nativa para tus usuarios.
Uso
Para comenzar a usar estas tabs tienes dos opciones: instalar el paquete de NuGet en tus tres proyectos o descargar el código fuente y colocarlo en tu aplicación.
Después, tienes que crear una página que derive de PlatformTabbedPage
:
Y como normalmente haces con las TabbedPage
originales, añadir las páginas hijo en el constructor. Es muy importante que notes cómo es que el ícono no termina en “.png”, ya que de otro modo las tabs no funcionarán correctamente en iOS:
Y obtendremos algo como esto (del lado izquierdo es la app creada con una TabbedPage
tradicional):
Descarga el código fuente para que puedas ver el ejemplo de este post.
Y ahora, si quieres saber cómo es que logré esta personalización, sigue leyendo.
PlatformTabbedPage
Entre las cosas que quise personalizar están el color del elemento seleccionado, el color del elemento deseleccionado, y en iOS el ícono del elemento seleccionado, ya que como viste en las imagenes anteriores en Android resulta un poco complicado resolver a primera vista qué elemento estamos viendo, mientras que en iOS resulta un poco extraño que el ícono del elemento seleccionado permanezca igual que los otros.
Creación del renderer
Comenzamos por definir una clase que derive del tipo de página que vamos a personalizar
Luego definimos las propiedades, con su respectiva BindableProperty
para permitir que se establezcan bindings a ellas:
La descripción de las propiedades es la siguiente:
SelectedColor
: El color del elemento seleccionadoBarBackgroundColor
: El color de fondo de la barra, decidí ocultar connew
la implementación por default, ya que voy a controlar el comportamiento de esta propiedad dentro de cada rendererBarBackgroundApplyTo
: Una enumeración que indica en qué plataformas modificaremos el color de la barra, y es que en mi opinión en iOS es un poco “antinatural” cambiar el color de la barra.
Además cree unos métodos de extensión para trabajar con los colores, haciéndolos más claros o más oscuros además de uno que ayuda a decidir si un color es claro u obscuro, puedes encontrar más detalles en el código fuente.
Ahora sí, vamos a ver la implementación en cada plataforma:
iOS
(para este renderer me basé por completo en la implementación de la app Evolve de Xamarin)
En iOS vamos a crear un renderer que derive de TabbedRenderer
:
Después definimos unas cuantas propiedades una para acceder al la instancia en forms de PlatformTabbedPage
y otro par para almacenar los colores por default de la UITabBar
original:
Si alguna vez has escrito un custom renderer ya sabrás que el método OnElementChanged
es llamado cada vez que se va a renderizar en pantalla el control, es por eso que dentro de él asignamos (y desasignamos) un evento que nos permitirá estar al tanto de cuando las propiedades de la barra cambien en el proyecto de forms.
Además de recuperar los colores por default del TabBar en caso de que los necesitemos más adelante.
Una vez hecho esto llamamos a un par de métodos que nos servirán para asignar los colores que deseamos.
Ahora toca el turno de “rellenar” los íconos, y digo “rellenar” porque en realidad es necesario que hayas creado un par de íconos por cada tab, uno que se muestre por default y otro que se muestre cuando la tab está seleccionada.
El truco aquí radica en que la API de iOS permite establecer dos imágenes una seleccionada y otra deseleccionada, y eso es precisamente lo que hace este renderer: toma el ícono, le añade el sufijo “_active” y lo coloca como la imagen que debe mostrarse cuando el elemento está seleccionado:
Y básicamente eso es todo, no se requiere de más gracias a la API que nos otorga iOS y a la la propiedad SelectedImage
.
Android
Para Android el renderer del que debemos derivar es TabbedPageRenderer
… sí, distinto al de iOS:
Se necesitan unas cuantas propiedades para preservar los colores por default:
En Android una página de pestñas está compuesta normalmente por un par de elementos independientes: un ViewPager
y un TabLayout
que se coordinan entre ellos para funcionar como un solo control, al ser parte central de este renderer también necesitamos tener una referencia a ellos a nivel de clase:
Ahora, dentro del importantísimo método OnElementChanged
obtendremos las referencias el par de controles declarados arriba. El renderer contiene ambos, sin embargo no los tiene directamente accesibles si no que son del tipo View
, es por eso que se usa is
para identificarlos y después hacer el cast de manera segura:
Obtenemos el color por default y establecemos los colores de la barra:
A diferencia de iOS, en Android tendremos que hacer uso de un par de métodos que son llamados cada vez que se selecciona/deselecciona una tab, es por eso que también son asignados dentro de el método principal:
Por último establecemos el color de todos los íconos en la barra de pestañas, y marcamos cono seleccionado el primer elemento mediante un pequeño método auxiliar:
Ahora si, la “magia” de los métodos que son llamados cuando se slecciona o deselecciona una pestaña: básicamente consiste en aplicar un filtro de color al ícono de la tab seleccionada, y dependiendo de qué método se haya llamado aplicar el color adecuado:
Y eso es todo… básicamente el renderer de Android es un poco más complicado que el de iOS, pero nada que sea del otro mundo.