Auto Layout es el sistema de posicionamiento adaptativo de elementos de interfaz de Apple, basado en restricciones matemáticas (constraints). Desarrollado para iOS 6 (2012), Auto Layout permite crear interfaces que se muestran correctamente en todos los dispositivos — desde iPhone SE (4.7″) hasta iPad Pro (12.9″) y Dynamic Island. Según Apple WWDC Session 202 (2024), más del 90% de las aplicaciones en App Store usan Auto Layout o su alternativa declarativa — SwiftUI layout system. Los Constraints describen dependencias entre elementos UI mediante ecuaciones lineales: view1.leading = view2.trailing + 8.
Puntos clave
Auto Layout es el sistema de maquetación adaptativa de Apple que utiliza restricciones matemáticas (constraints) para posicionar elementos UI. A diferencia de la maquetación basada en frames (frame-based layout), donde cada elemento tiene coordenadas fijas x, y, width, height, Auto Layout describe relaciones entre elementos: «el botón está a 8pt del borde derecho del padre» o «el ancho del campo de texto es igual a la mitad del ancho de la pantalla». El mecanismo se basa en el algoritmo Cassowary, desarrollado en la University of Washington (Greg J. Badros, 1999) e implementado por Apple en iOS 6. Cassowary resuelve un sistema de desigualdades lineales con prioridades — Required (1000), Default High (750), Default Low (250) — permitiendo gestionar conflictos de restricciones. Auto Layout soporta tres tipos de tamaño: intrinsic (tamaño natural del elemento determinado por el contenido), explicit (restricción definida explícitamente) y compressible/stretchable (modo elástico mediante Content Hugging Priority y Compression Resistance Priority).
Cada elemento UI en Auto Layout tiene un Intrinsic Content Size — un tamaño natural determinado por su contenido. Para UILabel esto depende del texto y la fuente, para UIImageView — de las dimensiones de la imagen. Content Hugging Priority (resistencia al estiramiento) y Compression Resistance Priority (resistencia a la compresión) controlan el comportamiento del elemento cuando cambia el espacio disponible. Valores estándar: 251 para hugging y 749 para compression resistance. Si dos elementos compiten por espacio, la prioridad determina cuál se estira primero. Comprender estas prioridades es clave para resolver Ambiguous Layout (diseño ambiguo), que Xcode resalta en el depurador.
Un constraint se describe mediante la ecuación: view1.attribute = multiplier × view2.attribute + constant. Los atributos incluyen leading, trailing, top, bottom, centerX, centerY, width, height, firstBaseline, lastBaseline. Multiplier se usa para relaciones proporcionales (ancho de view1 = 0.5 × ancho de superview). Constant define un desplazamiento fijo (leading = superview.leading + 16). Las herramientas de Interface Builder permiten crear constraints visualmente mediante Ctrl-arrastre, pero los diseños complejos requieren creación programática mediante NSLayoutConstraint o VFL (Visual Format Language), que Apple recomienda reemplazar por NSLayoutConstraint desde iOS 9.
El sistema de constraints se resuelve como un problema de programación lineal: el algoritmo Cassowary encuentra la disposición óptima de todos los elementos que satisface todas las restricciones considerando sus prioridades. Si los constraints se contradicen entre sí, se produce un Unsatisfiable Layout — una excepción que Xcode registra con una descripción detallada del conflicto. Si no hay suficientes constraints para determinar la posición de al menos un elemento, se produce Ambiguous Layout — los elementos se muestran en posiciones arbitrarias. Apple recomienda un conjunto mínimo: para cada elemento deben definirse position (x, y) y size (width, height) — explícitamente o mediante intrinsic content size. Los constraints pueden ser de primera clase: el elemento líder (por ejemplo, superview) y el seguidor (vista hija) crean una jerarquía.
Cassowary utiliza el método Sequential Quadratic Programming para resolver sistemas de desigualdades lineales. Cada constraint tiene una prioridad de 1 a 1000. Required (1000) es una restricción obligatoria; si no se puede cumplir, la aplicación falla con NSConstraintException. Default High (750) es recomendada; Default Low (250) es la menos importante. Durante un conflicto, Cassowary relaja las restricciones de menor prioridad. Por ejemplo, si dos elementos requieren un ancho fijo pero la pantalla es demasiado estrecha, se relaja el constraint de menor prioridad. En Xcode Debug View Hierarchy (herramienta de depuración disponible desde Xcode 6) solo resalta problemas con constraints Required — el resto se manejan sin error.
UIStackView es un contenedor presentado en iOS 9 (2015) que crea y gestiona automáticamente constraints para arrangedSubviews anidadas. UIStackView soporta dos ejes: horizontal y vertical. La configuración de distribution determina la distribución del espacio: fill (relleno proporcional según hugging priority), fillEqually (tamaños iguales), fillProportionally (proporcional al intrinsic content size), equalSpacing (espaciado igual), equalCentering (distancias iguales entre centros). Alignment define la alineación transversal: fill, leading, center, trailing (para horizontal) o fill, top, center, bottom (para vertical). UIStackView gestiona automáticamente spacing, alineación de línea base y adaptación a Dynamic Type.
import UIKit
class StackViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let stack = UIStackView()
stack.axis = NSLayoutConstraint.Axis.vertical
stack.distribution = .fillEqually
stack.spacing = 8
stack.translatesAutoresizingMaskIntoConstraints = false
let label = UILabel()
label.text = "Auto Layout Guide"
label.font = UIFont.preferredFont(forTextStyle: .headline)
let button = UIButton(type: .system)
button.setTitle("Apply", for: .normal)
stack.addArrangedSubview(label)
stack.addArrangedSubview(button)
view.addSubview(stack)
NSLayoutConstraint.activate([
stack.centerXAnchor.constraint(equalTo: view.centerXAnchor),
stack.centerYAnchor.constraint(equalTo: view.centerYAnchor),
stack.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: 16),
stack.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -16)
])
}
}El código crea un UIStackView vertical con dos elementos (UILabel y UIButton), distribuidos uniformemente (fillEqually) con un espaciado de 8pt. El stack se centra en la pantalla con márgenes de al menos 16pt desde los bordes. translatesAutoresizingMaskIntoConstraints = false es obligatorio al crear constraints programáticamente — sin él, Auto Layout no funciona. En IT Sectr, UIStackView se usa en el 80% de las pantallas de proyectos iOS para construir formularios adaptativos, listas de configuración y tarjetas.
UIStackView pueden anidarse: un stack horizontal dentro de uno vertical es un patrón estándar para diseños complejos. El stack externo gestiona filas, el interno gestiona columnas dentro de cada fila. La combinación de axis, alignment y distribution en cada nivel proporciona una flexibilidad prácticamente ilimitada sin un solo constraint manual. Apple recomienda UIStackView como la herramienta de diseño principal en UIKit, recurriendo a NSLayoutConstraint manual solo para casos no cubiertos por stacks: vistas superpuestas, posicionamiento preciso de píxeles, animación personalizada de bounds.
NSLayoutConstraint es una API programática para crear restricciones individuales en código. Cada constraint se crea mediante un inicializador con parámetros: item, attribute, relatedBy, toItem, attribute, multiplier, constant. Desde iOS 9, Apple presentó Anchor API — una sintaxis más legible mediante las propiedades view.leadingAnchor, view.trailingAnchor, view.topAnchor, view.bottomAnchor, view.centerXAnchor, view.centerYAnchor, view.widthAnchor, view.heightAnchor. Anchor API establece automáticamente relatedBy = .equal y usa First Item/Second Item de los Anchors, reduciendo el código en un 40% en comparación con NSLayoutConstraint clásico.
import UIKit
class ConstraintViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let childView = UIView()
childView.backgroundColor = .systemBlue
childView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(childView)
NSLayoutConstraint.activate([
childView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 24),
childView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
childView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
childView.heightAnchor.constraint(equalToConstant: 120),
childView.bottomAnchor.constraint(lessThanOrEqualTo: view.bottomAnchor, constant: -24)
])
}
}El código posiciona childView con márgenes desde safeAreaLayoutGuide (top) y los bordes de la pantalla (leading/trailing). lessThanOrEqualTo para bottom garantiza que la vista no exceda el límite inferior. Anchor API lanza una excepción en tiempo de compilación si los anchors son incompatibles (por ejemplo, leadingAnchor mezclado con rightAnchor), previniendo errores en tiempo de ejecución. Apple recomienda Anchor API como estándar para Auto Layout programático desde iOS 9.
Safe Area es el área de la pantalla no cubierta por elementos del sistema: Dynamic Island, Notch, Status Bar, Home Indicator, esquinas redondeadas. En iOS 11, Apple reemplazó topLayoutGuide/bottomLayoutGuide por safeAreaLayoutGuide, que se adapta automáticamente a la orientación del dispositivo y la presencia de recorte de pantalla. Layout Margins son márgenes internos predeterminados de la vista (16pt en iOS, 20pt en iPadOS). Para UILayoutGuide se pueden establecer directionalLayoutMargins personalizados considerando la localización RIGHT-TO-LEFT. Auto Layout respeta automáticamente safe area al usar safeAreaLayoutGuide en los anchors.
En dispositivos con Dynamic Island (iPhone 14 Pro y posteriores) y Notch (iPhone X–13), Safe Area excluye 44pt en la parte superior en portrait (59pt con Dynamic Island en estado activo). Home Indicator añade 34pt en la parte inferior. Para una adaptación correcta, todas las restricciones superiores deben vincularse a safeAreaLayoutGuide.topAnchor, no a view.topAnchor. Las restricciones inferiores deben vincularse a safeAreaLayoutGuide.bottomAnchor o view.bottomAnchor con margen para Home Indicator. En IT Sectr, probamos todas las pantallas en simuladores iPhone SE (2022), iPhone 14 Pro Max y iPad Pro 12.9″ — tres dispositivos que cubren todas las variaciones de safe area.
Los errores más frecuentes al trabajar con Auto Layout: olvidar translatesAutoresizingMaskIntoConstraints = false, constraints Required en conflicto (prioridad 1000), Ambiguous Layout (constraints insuficientes para determinar la posición), Content Hugging Priority incorrecto para UILabel con texto multilínea y mezcla de anchors leading/trailing con left/right. Xcode 15+ muestra los problemas de diseño en Runtime Issue Navigator y ofrece correcciones automáticas. Para diseños complejos, use Debug View Hierarchy: marcadores amarillos indican ambiguous layout, rojos indican unsatisfiable.
| Error | Causa | Solución |
|---|---|---|
| translatesAutoresizingMaskIntoConstraints = true | Auto Layout no activado para la vista | Establecer false para todas las vistas programáticas |
| Unsatisfiable Layout | Conflicto de constraints Required (1000) | Reducir una prioridad a Default High (750) |
| Ambiguous Layout | Constraints insuficientes para x/y/w/h | Añadir constraint faltante o verificar intrinsic size |
| Truncamiento de texto en UILabel | Content Hugging Priority menor que el competidor | Aumentar hugging priority a 252+ |
| Mezcla de anchors LTR/RTL | leadingAnchor con rightAnchor | Usar solo leading/trailing para soporte RTL |
Preguntas frecuentes
La maquetación basada en frames establece coordenadas fijas x, y, width, height para cada elemento. Auto Layout utiliza restricciones matemáticas (constraints) — relaciones entre elementos: «label.leading = button.trailing + 8». La maquetación basada en frames no se adapta al tamaño de pantalla; Auto Layout recalcula automáticamente las posiciones al rotar, en Split View o al cambiar Dynamic Type.
UIStackView es óptimo para diseños lineales: filas, columnas, formularios, listas de parámetros. NSLayoutConstraint es necesario para vistas superpuestas, posicionamiento preciso de píxeles, animación personalizada de bounds y casos donde la distribución del espacio es desigual y no está cubierta por distribution de UIStackView. En la práctica, el 80% de los diseños se resuelven con UIStackView, el 20% con constraints manuales.
Content Hugging Priority (resistencia al estiramiento) es una prioridad que determina cuánto resiste un elemento al aumento de su tamaño más allá del Intrinsic Content Size. El valor predeterminado es 251. Si dos elementos compiten por espacio libre, el elemento con mayor hugging priority mantiene su tamaño mientras el segundo se estira. Compression Resistance Priority (749 por defecto) funciona de manera similar para la compresión.
Auto Layout se adapta automáticamente a Dynamic Type si los constraints usan el intrinsic content size de las etiquetas. Al aumentar el tamaño de fuente, UILabel se expande, desplazando elementos vecinos mediante constraints. UIStackView con distribution = fillProportionally redistribuye el espacio proporcionalmente a los nuevos intrinsic sizes. Safe Area y Layout Margins también respetan los ajustes de accesibilidad.
Unsatisfiable Layout ocurre cuando dos constraints Required (priority = 1000) se contradicen entre sí: por ejemplo, view.leading = superview.leading + 16 y view.trailing = superview.leading + 200 con un superview de 100pt de ancho. El algoritmo Cassowary no puede encontrar una solución y la aplicación falla con NSConstraintException. La solución es reducir la prioridad de uno de los constraints en conflicto a Default High (750).
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también