Implementando AiForms.Dialogs con Xamarin.Forms

Fabricio Bertani
8 min readDec 9, 2020

If you prefer to read this article in English, please follow this link

Aviso: el propósito de esta publicación no es ofender ni insultar a ningún diseñador gráfico o UI/UX, sino burlarme un poco de mí mismo y de mi falta de habilidades de diseño.

Por lo general, trabajamos en equipos, a veces pequeños, otras veces en equipos grandes, pero casi todos los equipos tienen al menos un diseñador de UI/UX o alguien de parte del cliente proporciona el diseño de nuestros proyectos.
Ocasionalmente, los diseñadores se vuelven demasiado creativos y nos piden que hagamos algunos controles poco convencionales o algo aún más difícil, como algunos alertas personalizadas!!!

Echemos un vistazo a la imagen a continuación para apreciar el más increible diseño de un popup de alerta, si nuestra aplicación fuera como un sitio web de la década pasada…

Un popup super creativo!

Como podemos ver, nuestro popup especial no encaja con la biblioteca de dialogs integrada de Xamarin.Forms.
Tampoco podemos lograr la tarea con la gran y ampliamente utilizada biblioteca Acr.UserDialogs.
Si seguimos buscando, podríamos encontrarnos con otro plugins muy popular, por supuesto que estoy hablando de Rg.Plugins.Popup. Aparentemente parece ser lo que necesitamos, pero como tenemos almas curiosas e inquietas, seguimos investigando un poco más, solo por si acaso, hasta que nos topamos con esta pequeña pero poderosa biblioteca llamada AiForms.Dialogs.

La llamo pequeña, porque no es ampliamente conocida o utilizada como su contrincante, esta librería tiene casi 30 mil descargas en Nuget contra más de 2 millones de Rg.Plugins.Popup.

Vamos a compararlas!

Rg.Plugins.Popup:

  • Te permite crear páginas de Xamarin.Forms y ejecutarlas como popup o alerts que se pueden ser compartidas en iOS, Android, UWP y macOS.
  • ¡Proporciona animaciones geniales!
  • La implementación se basa puramente en Xamarin.Forms, solo usa renderers de vistas de Xamarin.Forms en el lado nativo.
  • Utiliza su propio sistema de navegación para ir hacia adelante y atrás en las páginas emergentes.
  • Fácil de implementar pruebas unitarias con él.

AiForms.Dialogs:

  • Te permite crear páginas de Xamarin.Forms e iniciarlas como un alert, un toast o un loading indicator, que se pueden compartirse en iOS y Android.
  • Te permite crear tus propias animaciones.
  • Las implementaciones son nativas (usando DialogFragment en Android y UIPresentationController en iOS, por ejemplo).
  • Incluye dialogs y loading reutilizables, esto significa que los métodos de dispose no se ejecutan para reutilizarlos durante el ciclo de vida de la página.
  • No es necesario utilizar ninguna navegación personalizada.

Como podemos ver, Rg.Plugins.Popup podría ser una gran opción, principalmente porque admite una mayor gama de plataformas y pruebas unitarias, pero AiForms.Dialogs ofrece loadings y toast personalizables que incluso se basan en implementaciones nativas. ¡Nuestro loco diseñador estaría realmente feliz!

Manos a la obra!

Primero necesitamos instalar el paquete nuget AiForms.Dialogs en nuestros proyectos de Forms, Android e iOS.
Recuerda que debes inicializar el paquete en Android, después de la inicialización de Xamarin.Forms:

AiForms.Dialogs.Dialogs.Init(this);

Luego, en nuestro proyecto Xamarin.Forms, crearemos un ContentView normal, pero lo cambiaremos para que sea un DialogView y crearemos nuestra vista como siempre, no sin antes agregar algunas pequeñas propiedades adicionales a nuestro DialogView base:

  • OverlayColor: el color de superposición de fondo para nuestro alert (el predeterminado es blanco o transparente).
  • UseCurrentPageLocation: de acuerdo con la documentación del plugin, esta propiedad booleana definirá si nuestro alert se alineará con los bordes de la ventana o con el área de la página actual. En nuestro caso lo configuraremos como falso.
  • IsCanceledOnTouchOutside: esta propiedad booleana simplemente definirá si el usuario puede cerrar el alert tocando el área fuera de ella. En nuestro caso lo configuraremos como falso.

Nota: Si setea la propiedad BorderColor, recuerda agregar un color de fondo al contenido de DialogView, de lo contrario, tomará BorderColor como BackgroundColor del contenido.

Entonces este será el XAML de nuestra alerta:

Y no te olvides de cambiar el tipo base de ContentView a DialogView en el code behind.
Tampoco te olvides de configurar correctamente el DialogNotifier para los botones de acción, estos son realmente importantes en caso de que estemos escuchando los eventos para saber qué opción elige el usuario.

Y por último necesitamos abrir el dialog llamando a la abstracción Dialog.Instance, pero no olvidemos que este es un método asíncrono y por lo tanto debemos usar la palabra clave await, así que podemos usar Device.BeginInvokeOnMainThread si no estamos dentro de un método de asíncrono.
El método ShowAsync<TDialogView>() devuelve una Task<bool> que se establece a través de los métodos DialogNotifier.Cancel() y DialogNotifier.Complete(), los cualespuede ser usados para ejecutar otras partes de nuestro código en cada respuesta.

Este es nuestro resultado en ambas plataformas:

¡Los sueños de nuestro diseñador loco se hacen realidad!

Mientras le contamos al diseñador acerca de las bondades que ofrece nuestra recientemente descubierta herramienta, él ya está pensando en su próxima loca solicitud…

Resulta ser que nuestro diseñador ama a Ryan Reynolds (¿quién no, verdad?). Por lo tanto, ahora nos solicita un loading a que contenga una cara animada de Reynolds, junto con una cita inspiradora, ¡así cumpliremos sus deseos!

Como hicimos anteriormente, crearemos otro ContentView, cambiaremos el tipo base a LoadingView esta vez, luego establezcamos OverlayColor en gris con transparencia y finalmente agreguemos nuestro contenido dentro de un StackLayout.

Cambiamos el tipo base a LoadingView en el code behind, luego crearemos la animación en el método constructor y la consumiremos con los métodos RunPresentationAnimation y RunDismissalAnimation proporcionados por el plugin para ejecutar y destruir la animación.

¡Veamos el resultado final!

Nuestro diseñador loco y Ryan Reynolds estarían muy contentos con el resultado.

Ahora decidió que deberíamos darle advertencias a los usuarios mediante un toast utilizando la siguiente guía

¿Más ComicSans?

Una vez más, crearemos un nuevo ContentView, cambiaremos el tipo base a ToastView y esta vez necesitamos establecer algunas propiedades:

  • HorizontalLayoutAlignment: cómo se colocará horizontalmente. En nuestro caso lo configuramos en Fill.
  • VerticalLayoutAlignment: dónde se colocará el toast verticalmente. En nuestro caso, lo configuramos en End para colocarlo en la parte inferior de la pantalla.
  • OffsetY: si colocamos el toast en la parte superior o inferior de la pantalla, necesitaremos usar esta propiedad para ajustar la posición, especialmente con iOS porque no respetará el ajuste del SafeArea. En nuestro caso lo configuramos en -35.
  • Duration: expresada en milisegundos, esto determinará cuánto tiempo estará visible el toast en pantalla. En nuestro caso lo configuramos en 3000.

Este será el XAML de nuestro toast:

No olvidemos cambiar el tipo base a ToastView en el code behind. También recuerdemos que es posible agregarle animaciones.

¡Veamos el resultado final!

Un hermoso toast personalizado

A nuestro diseñador loco le gustó tanto el diseño del alert que quiere usarla para todos los que aparezcan en la aplicación.
Para realizar esta tarea y anticiparnos a una posible solicitud especial futura del mismo, creemos una clase helper que se pueda registrar como singleton, por lo que nos ayudará a usarla tanto desde nuestros views como desde nuestros viewmodels.

Definamos los métodos de nuestra interface

Si lo desglosamos:

  • Un método ShowAlert para mostrar nuestros alerts, con algunos parámetros requeridos y algunos parámetros opcionales, que devuelve un bool, el cual indica si el alert fue cancelado o aceptado.
  • Dos métodos ShowLoading, aprovechando la herencia de C#, definimos un método para loading regulares y otro que toma un parámetro para mostrar un mensaje mientras la vista de loading está visible.
  • Un método sencillo de HideLoading para ocultar nuestro loading.
  • Un método especial ShowLoadingWithProgressAsync para mostrar un conteo de progreso al cargar, por ejemplo, si queremos que los usuarios conozcan el progreso de la descarga de un archivo. Se necesita un Func<IProgress<double>, Task> como parámetro para pasarlo al loading y un texto para mostrar algún mensaje personalizado mientras el loading está visible.
  • DisplayToast nos ayudará a mostrar un simple toast, pasamos un mensaje y duración expresada en milisegundos, definimos una duración predeterminada de 3 segundos.

Y ahora la implementación:

Primero definimos la implementación de nuestro singleton para el helper.

Echemos un vistazo más de cerca a la implementación de ShowAlert:

Es casi lo mismo que nuestro WinMoneyDialogView, pero cambiamos los textos con algunos binding: DialogText, AcceptText y CancelText. Estos nombres pueden ser los que queramos, pero deben ser los mismos a la hora de crear la vista como podemos ver aquí:

await Dialog.Instance.ShowAsync<DefaultDialogView>(new
{
DialogText = dialogText,
AcceptText = acceptText,
CancelText = cancelText
});

El plugin se encargará de convertir esos enlaces.

Ahora, si echamos un vistazo a la primera implementación de ShowLoading, simplemente llamamos a la implementación predeterminada del loading del plugin y establecemos un mensaje predeterminado.
En la segunda implementación, llamamos primero al método Show y luego al método SetMessage con nuestro mensaje personalizado.
HideLoading simplemente llamará al método Hide del plugin.

ShowLoadingWithProgressAsync, al igual que ShowAlert, será un método asíncrono, simplemente pasamos la función y el mensaje al método StartAsync, que toma la misma Func<IProgress<double>, Task> y el mensaje.

Finalmente, para el método DisplayToast, necesitamos crear una nueva vista de toast:

Al igual que ShowAlert, necesitamos pasar el binding

Toast.Instance.Show<DefaultToastDialogView>(new
{
ToastText = toastText,
Duration = duration
});

Hora de las pruebas

Para probar nuestra implementación del helper, crearemos una vista y un viewmodel asociado a ella.

Añadimos los bindings a nuestro viewmodel y alguna implementación en el code behind para probar.

  • OpenRegularLoading llama a nuestra instancia de nuestro DialogHelper y mostrará un loading durante 3 segundos.
Una vista de loading simple
  • OpenLoadingWithCustomText tomará el texto del Entry y mostrará el loading con él.
Una vista de loading con texto personalizado
  • OpenDialogWithCustomText esta fue la solicitud original de nuestro diseñador, le pasamos un mensaje personalizado y definimos “Yes”/“No” como opciones.
Nuestro alert especial ahora admite cualquier texto como mensaje
  • OpenFakeDownloadLoading aquí simularemos una descarga para probar el progress.
Un loading con indicador de progreso
  • OpenRegularToast_Clicked implementamos este método en el code behind de nuestro xaml para probar si nuestro helper también funciona allí. Le pasamos algún texto y la duración.
Un toast normal que se muestra en el centro de la pantalla.

Eso es todo amigos!

Creo que este es un plugin realmente útil y te recomiendo que lo pruebes y, si te gusta, dejes una estrella en el repositorio porque Kamu (el creador) realmente se lo merece.

También puede ver mi repositorio de ejemplo completo para esta publicación en GitHub.

Gracias por leer y a seguir codeando mientras Vincent Connare se ríe desde el infierno 😁

--

--

Fabricio Bertani

I'm a mobile application developer, mainly focused on multiplatform technologies such as Xamarin.Forms and Flutter.