Atomic Design con flutter. Metodología de diseño

Atomic Design con flutter. Metodología de diseño

Por efectos de la pandemia me he puesto aprender un montón de cosas y entre estas esta programar en Flutter/Dar, quise hacer un desarrollo siguiendo una metodología que se llama Atomic Design o diseño atómico.

Disclaimer: Puesto que estoy aprendiendo ambas cosas a la vez tanto flutter como el modelo de diseño atómico, es probable que tenga errores en cuanto a diseño concepto e implementación, así que siéntete libre de comentarlos y o de corregir el código en GitHub.

Flutter

Flutter Logo

Es un framework/SDK desarrollado por google para crear aplicaciones multiplataforma tales como: Androi, iOS, Web, y es el Framework oficial de su nuevo sistema Fuchsia, el cual aun no ve la luz, pero bueno es otra historia, se distingue por crear interfaces de usuario de una forma declarativa usando código, nada de estar editando xml, xaml o story boards y por su alto rendimiento grafico.

Dart

Dart Logo
Dart Logo

Es un lenguaje de programación orientado a objetos igualmente creado por google, en la web se podría decir que es una competencia a TypeScript.

Atomic Design

Atomic Design
Atomic Design by genitalico

Es una metodología que propone la separación del diseño basado en elementos modulares para poder reutilizarlos, pero parte de la primicia en la que cada elemento debe funcionar tanto individualmente como en conjunto, esta metodología fue creada por Brad Frost.

No quiero explayarme mucho en que es cada cosa, ya que en las respectivas webs lo explican mucho mejor así que pasemos a lo divertido.

Login Atomico

Empece diseñando la vista mas sencilla del mundo es la siguiente:

Ejemplo Login
Ejemplo Login by genitalico

Esta vista consta de solo 5 elementos, que son:

  • Imagen
  • Campo correo
  • Campo contraseña
  • Circulo de progreso
  • Botón entrar

Estos los voy a separar en átomos de acuerdo al modelo atómico como sigue:

  • Campo de Texto
  • Imagen
  • Circulo de progreso
  • Boton

Como es una ventana muy simple la separación de elementos quedo de manera similar a un diseño tradicional, pero tal cual deje los elementos en el código estos pueden ser altamente reutilizados.

El mockup del desarrollo atómico final quedo cómo sigue.

Mockup Atomic Design
Mockup Atomic Design by genético

Código

Flutter tiene similitudes con ReactJS en cuanto a los estados de los componentes en este caso son los widgets incluso ambos tiene un método setState, en flutter todo es un widget quédense con eso.

Hay dos clases interesantes en flutter StatelessWidget y StatefulWidget, la primera es para widgets sin estado, esto es widgets o hablando de la interfaz son elementos que no mutan al igual que por ejemplo un objeto inmutable en POO, de hecho es lo mismo a nivel de código. El segundo es un elemento que va a mutar, a nivel visual es un elemento que dada algunas condiciones cambiara, por ejemplo de color blanco a rojo etc.

La version de flutter que use es la 1.12.13+hotfix9 y dart 2.7.2.

El código para esa vista es bastante simple mas allá de la complejidad de flutter para crear los elementos pero a nivel arquitectura y siguiendo la metodología de diseño atómico, lo deje de la siguiente manera:

Sobre la estructura de nombres fue lo mejor que se me ocurrió para agilizar el post y no ahondar mucho en buenas practicas.

Atomos

TextFieldStandard1

Es el diseño de uno de los campos de texto, el cual recibe algunos parámetros:

  • hintText. Es el texto que se muestra pero se oculta cuándo se escribe dentro.
  • prefixIcon. Es el icono que se muestra a la izquierda del campo.
  • obscureText. Este es un valor boleado que oculta el texto en puntos, ideal para contraseñas y que lo pongo en true en el campo de password.
  • textColor. Es el color del hinText.
  • controller. Es un objeto de tipo TextEditingController y lo uso para para recoger el valor que se escriba dentro del campo.
  • onTap. Es un tipo VoidCallback que a su vez es solo un alias para una función sin retorno, este sirve para implementar algún evento cuando toquen el campo.
  • FocusNode. Objeto que sirve para obtener o aplicar foco a un elemento, este me sirve para solventar un problema de dart.

CPIStandard1

CPIStandard1

Este es el circulo de progreso animado, es bastante simple y solo esta envuelto en una clase Opacity, esto por que necesitaba una manera de ocultarlo, mostrarlo y manteniendo su espacio en el diseño, así que solo recibe un parámetro para esta acción.:

  • opacity. Es un valor double que en este caso representa el nivel de opacidad, que va de 0 a 1, para este caso 1 es mostrar 0 ocultar.

BtnStandard1

Simplemente es el botón y recibe los parámetros:

  • color. Color de fondo.
  • textColor. El color del texto
  • text. El texto del botón.
  • onPressed. Tipo VoidCallback para pasar la función a ejecutar cuando se toque el botón.

Moleculas

EmailPassword

login password by genitalico
login password by genitalico

Esta es la única molécula en este diseño y consta de dos átomos que reciben distintos parámetros, esta molécula para no enredarme y terminar rápido internamente instancia y pasa parámetros para los átomos, aquí lo ideal debería ser, tener objetos para pasar los valores a cada átomo y encapsular estos en dos objetos a pasar como valor a la molécula, puesto que así podemos ir de arriba hacia abajo pasando mensajes al construir una plantilla u organismo.

Widget build(BuildContext context) {
// TODO: implement build
return Column(
children: <Widget>[
TextFieldStandard1(
hintText: "Correo",
prefixIcon: Icons.mail,
controller: _emailController,
onTab: _onTap,
textColor: _emailColor,
focusNode: focusNodeEmail),
SizedBox(height: 15),
TextFieldStandard1(
hintText: "Contraseña",
prefixIcon: Icons.lock,
controller: _passwordController,
onTab: () {},
obscureText: true)
],
);
}

Esta molécula es de tipo StatefulWidget debido a que el campo de correo cambia de color a rojo cuando van a presionar el botón y a blanco cuando tocan el campo mismo, de los dos átomos es el único que se recrea cuando cambia el estado de la molécula.

Organismo

Login

Ejemplo Login

Teniendo todo lo anterior es como se construye el organismo compuesto de un átomo imagen, el cual no vi la necesidad de extender ya que el objeto de imagen tiene el mismo propósito para esto.

El objeto es de tipo StatefulWidget, ya que este es el que controlara todo el flujo de cambios, con excepciones no todos los objetos internos se reconstruyen cuando el estado de este organismo cambia.

Aquí el único widget que cambia y se reconstruye es el Circulo de progreso que pasa de estar oculto a mostrarse, todo lo demás se instancia una sola vez.

Widget build(BuildContext context) {
double _marginlr = MediaQuery.of(context).size.width * 0.07;
// TODO: implement build
return Container(
margin: EdgeInsets.only(left: _marginlr, right: _marginlr),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AspectRatio(
aspectRatio: 1.7,
child: Image(
image: AssetImage("assets/images/80bitslogo.png"),
),
),
SizedBox(height: 60),
this._emailPassword,
SizedBox(height: 15),
CPIStandard1(opacity: this._opacity),
SizedBox(height: 15),
_btn1
],
),
);
}

Para esto ultimo me di la libertad de que el organismo ya estuviera totalmente construido, tanto a nivel diseño como a nivel de instancia de los otros objetos colores, texto, etc, esto por la rapidez en que necesitaba programar.

La pregunta es como se sube de nivel hacia una plantilla?, pues mi idea es que en flutter puesto que es POO, al menos desde mi perspectiva una plantilla puede ser un organismo como es mi caso o el conjunto de organismos con la diferencia es que si son dos o mas seria una instancia separada donde se unan los organismos, aquí la cuestión radicara que habrá que hacer modelos para pasar parámetros y construir todo lo que se tenga que mostrar, colores, texto, etc.

Así que una plantilla en mi opinión quedaría como un objeto flutter que recibe sus parámetros y este los comunica hasta los átomos.

dibujo plantilla by genitalico
dibujo plantilla by genitalico

Problemas

Debido a que llevo aproximadamente 20 días aprendiendo flutter no estuve exento de problemas, uno de estos fue con la idea que tenia de que en mi molécula de campos solo se reconstruyera el campo de correo para obtener mejor performance y ahorrar memoria, muy mínima pero hay ahorro.

La idea parte de que el campo contraseña es un objeto constante que no necesita cambia durante todo el ciclo de la vista, por lo que en en tiempo de compilación de hacen las optimizaciones necesarias para ahorrar memoria.

Pues bien al existir dos o mas campos y uno de ellos va a cambiar su estado, flutter tiene un problema con el “foco” y falla al momento de un rebuild y truena toda la vista, el issue ya lo tienen en mente para ser resuelto, pueden ver la discusión aquí y una solución aquí.

Mi solución y si no quieres usar lo que proponen en la web de flutter es que la molécula se recree cada vez eso genera que ambos átomos se vuelvan a instanciar pero el de correo con un color distinto y para eso cambiar a un widget sin estado la molécula, claro que ahí se perdería el performance de solo instanciar uno y para ser honesto es indiferente en teléfonos actuales que se construyan dos objetos nuevamente en lugar de uno, aparte que el GC actuara de manera eficiente liberando memoria.

Finalmente la vista de login quedo de la siguiente manera.

Si llegaste hasta aquí, toma el código!

Se libre de dejar tus comentarios y hacer un full request.

Fuentes

Libro online Atomic Design

Flutter

Dart

Fuchsia