Todo lo que NO querías saber sobre Auto Layout pero DEBES de saber

| Última modificación: 13 de marzo de 2024 | Tiempo de Lectura: 4 minutos

Algunos de nuestros reconocimientos:

Premios KeepCoding

Introducción a Auto Layout

Al definir el layout de una interfaz de usuario, a menudo queremos expresarlo en forma de una serie de requisitos y preferencias. Por ejemplo, en una App para OSX, podríamos tener una ventana como esta con la siguiente lista de requisitos y preferencias :
  1. La imagen debe de estar siempre a x1 del borde izquierdo.
  2. La imagen debe de estar siempre a x2 del borde derecho.
  3. La imagen debe de estar siempre a y1 del borde superior.
  4. La etiqueta debe de estar siempre a x1 del borde izquierdo
  5. La etiqueta debe de estar siempre a y2 del borde inferior.
  6. El botón debe de estar siempre a la misma altura que la etiqueta
  7. El botón debe de estar siempre a x2 del borde derecho.
  8. Me gustaría mucho que la etiqueta siempre tuviese espacio suficiente para mostrar todo su texto, pero si no puede ser, tampoco pasa nada.
“Size matters not, ... Look at me. Judge me by size, do you?” - Auto Layout
“Size matters not, … Look at me. Judge me by size, do you?”
“Size matters not, ... Look at me. Judge me by size, do you?”
“Size matters not, … Look at me. Judge me by size, do you?”
La gran diferencia entre los requisitos y las preferencias , es que las últimas no hace falta cumplirlas. Si se puede, bien, sino pues me aguanto. Eso sí, lo ideal es que si resulta imposible cumplir con una preferencia, se llegue lo más cerca posible. Cualquiera que haya intentado implementar este tipo de cosa por código, sabe que es el camino a la locura. A medida que tu interfaz se va haciendo más rica, la complejidad del código se dispara hasta llegar a ser intratable.
Tendría que haber alguna forma de expresar esa lista de requisitos y preferencias de forma declarativa y que el sistema se encargue de todo lo demás.

Prolog al rescate

Desde tiempos primordiales existe un lenguaje diseñado para resolver este tipo de problemas: Prolog. Y lo que es más, una de las mejores y más eficientes implementaciones de Prolog para este tipo de problemas, ha sido creada en España, en la Politécnica de Madrid: Ciao Prolog. En una vida anterior, cuando era joven e insensato, llegué a integrar un intérprete de Prolog en un programa para Windows para hacer algo parecido. Funcionaba muy bien, aunque sudé tinta china para comunicar Prolog y C++ vía COM (juventud, divino tesoro). Sin embargo, no serviría para algo como lo descrito, por una razón muy sencilla: en mi veloz Cyrix 486 tardaba un segundo en encontrar una solución (valores para cada una de las variables) que satisficiesen mis requisitos y preferencias. Además, si casi todo estaba resuelto y sólo faltaba uno de los requisitos, el sistema volvía a recalcularlo todo. Es decir, si estirase la ventana en horizontal, el sistema volvería a recalcularlo TODO, incluidos los requisitos que se refieren al eje vertical, malgastando tiempo y recursos.
Para una interfaz gráfica, necesitamos algo más rápido y gradual; es decir, que pueda aprovechar lo ya resuelto y sólo calcular lo que falta, en vez de siempre partir de cero. Ya que estamos, no estaría mal algo más sencillo que integrar y comunicar dos lenguajes absolutamente distintos como hice yo en un momento de locura.

Sistemas de Ecuaciones Lineales

Si te fijas en la lista de requisitos y preferencias, verás que se podría modelar como un sistema de ecuaciones lineales, todas con la siguiente pinta:
vista.propiedad = α vista2.propiedad + β
ó bien
vista.propiedad ≤ α vista2.propiedad + β
ó bien
vista.propiedad ≥ α vista2.propiedad + β
La preferencias serían lo mismo, pero con un extra: un prioridad más baja, que hace que no siempre se tengan que cumplir.
Por lo tanto, cada uno de los requisitos o preferencias se representaría mediante una ecuación lineal y una prioridad (alta para requisitos y baja para preferencias).
Para resolver este tipo de sistemas de ecuaciones, hay algoritmos estándar como el Simplex. También los hay algo más elaborados que aportan algunas ventajas más:
  • Permiten que β sea negativa y no solo positiva (siempre negatifo, nunca positifo).
  • Resuelven el sistema de forma gradual, en vez de recalcularlo todo desde cero.
Algo así es lo que necesitaríamos para poder deshacernos de la ingrata y compleja tarea de programar el layout de nuestras interfaces gráficas. ¿Existe? ¡Si, y se llama Cassowary!El Casuario, un pajarraco de Papua Nueva Guinea y Australia con muy malas pulgas

Cassowary & Auto Layout

Cassowary está implementado en C++ y ha sido diseñado precisamente para resolver de forma muy eficiente el problema que plantea el layout de interfaces gráficas. En 2011 Apple lo integró en Cocoa creando “wrappers” en Objective C, y al sistema resultante, le llamo Auto Layout. Cuando fue lanzado, no estaba del todo listo para el consumo humano, pero a fecha de hoy, con iOS7, sí que lo está y no hay disculpa para no usarlo. Su utilidad es cada vez mayor, dada la creciente variedad de dispositivos y tamaños. En estos momentos, Auto Layout está disponible para iOS y OSX y es lo bastante estable como para ser la opción por defecto para diseñar el layout de cualquier vista. Hay algunas excepciones que veremos luego, pero es junto con ARC, lo mejor que nos ha pasado a los desarrolladores Cocoa desde hace años. Auto Layout está diseñado para representar y resolver requisitos (constraints) entre vistas de una misma aplicación, pero Cassowary también ha sido usado para manejar el layout de ventanas de distintas aplicaciones. En concreto se trata del “Window Manager” scwm (Scheme Constraint Window Manager). Una App así para OSX sería fantástica, ya que te permitiría crear layouts de distintas Apps para tareas específicas (como hace por ejemplo Divvy) pero dinámicas: cuando cambias el tamaño de una ventana, las demás se adaptan.

Lo que no puede ser no puede ser, y además es imposible

Un “pequeño” detalle que no hemos citado hasta ahora es el siguiente: nuestra lista de requisitos y preferencias (de ahora en adelante restricciones (“constraints” en Inglés)) debe de tener solución. Podría no tenerla por dos razones:
  1. Está incompleta y por lo tanto ambigua. Por ejemplo, si indicamos la distancia de la imagen a los bordes superior, izquierdo e inferior de la supervista, el sistema no sabrá qué hacer con el borde derecho de la imagen. ¿Debe ir incrementando el ancho, o mantenerlo fijo?
  2. Es incoherente porque hay dos o más restricciones que son incompatibles. Por ejemplo, una indica que el borde derecho debe de estar a 10 puntos del borde derecho de la supervista y otra dice que tiene que estar a 20.
Xcode no siempre será capaz de detectar cuando un sistema de restricciones es irresoluble. Si lo detecta, te avisará en tiempo de compilación. Si no, se producirá una excepción en tiempo de ejecución, tu app se caerá y harás el ridículo. El que avisa… En el próximo capítulo, veremos cómo acceder a Casowary (Auto Layout) en Cocoa con Objective C.
Fernando Rodríguez

iOS Developer & Co-Fundador de KeepCoding

Posts más leídos