Aunque con la llegada de SwiftUI, la relevancia de la distribución automática está disminuyendo rápidamente, mientras que este mecanismo todavía se usa activamente, y la biblioteca puede ser útil para aquellos que crean (o cambian) la interfaz de usuario directamente en el código.
Este método de construir una interfaz tiene una serie de desventajas que limitan su uso:
- La creación de elementos NSLayoutConstraint es muy inconveniente.
- Mala visibilidad: mirar el código hace que sea difícil entender cómo se verá la interfaz de usuario.
- Mucho código de rutina. Para colocar cada vista se requiere la creación de un promedio de aproximadamente 3 restricciones, es decir, Tres líneas del mismo código.
- La laboriosidad de crear interfaces que cambian dinámicamente: es necesario guardar restricciones en variables separadas para que pueda cambiarlas más tarde, y también a menudo crear restricciones redundantes y "desactivar" las innecesarias.
El primer problema se puede resolver fácilmente envolviendo los métodos estándar para crear restricciones en algo más humano. Y esto ya está bien implementado, por ejemplo, en SnapKit , TinyConstraints y otras bibliotecas similares.
Pero aún tiene que escribir mucho del mismo tipo de código, y sigue habiendo problemas con la visibilidad y los cambios dinámicos en el diseño. UIStackView resuelve inteligentemente estos problemas, pero desafortunadamente, UIStackView tiene una personalización muy limitada de la posición de los elementos individuales. Por lo tanto, surgió la idea de un contenedor UIView que controla el diseño de la pila de sus subvistas, pero con la capacidad de personalizar individualmente la ubicación de cada subvista.
Este es el enfoque detrás de BoxView y ha demostrado ser muy efectivo. BoxView le permite eliminar casi por completo la creación manual de restricciones, casi toda la interfaz de usuario está formada como un sistema de BoxViews anidados. Como resultado, el código se ha vuelto mucho más corto y más visible, la ganancia es especialmente notable para las IU dinámicas.
BoxView es en muchos aspectos similar al UIStackView estándar, pero utiliza diferentes reglas para la colocación de subvistas: en él puede establecer sangrías y tamaños para cada subvista individualmente. Para crear un diseño, BoxView utiliza una matriz de BoxItems, que contiene todas las vistas que deben mostrarse e información sobre cómo organizarlas. Y esto no requiere mucho código en absoluto: la mayoría de los parámetros de diseño se toman por defecto y solo se especifican explícitamente los valores necesarios.
La propiedad esencial de BoxView es que solo crea las restricciones especificadas para las subvistas agregadas, y nada más. Por lo tanto, se puede usar sin restricciones junto con otras bibliotecas y métodos de diseño.
Como ejemplo, considere crear un inicio de sesión de formulario simple usando BoxView (el código de ejemplo completo con una descripción paso a paso está disponible en el proyecto BoxViewExample en github ).
Para crear dicho diseño en BoxView, basta con unas pocas líneas de código:
nameBoxView.items = [nameImageView.boxed.centerY(), nameField.boxed]
passwordBoxView.items = [passwordImageView.boxed.centerY(), passwordField.boxed]
boxView.insets = .all(16.0)
boxView.spacing = 20.0
boxView.items = [
titleLabel.boxed.centerX(padding: 30.0).bottom(20.0),
nameBoxView.boxed,
passwordBoxView.boxed,
forgotButton.boxed.left(>=0.0),
loginButton.boxed.top(30.0).left(50.0).right(50.0),
]
El elemento BoxItem se crea a partir de cualquier UIView utilizando la variable en recuadro, después de lo cual se puede establecer en sangría desde 4 lados, alineación, así como tamaños absolutos o relativos.
Cualquier elemento de diseño puede agregarse y eliminarse libremente (incluso con animación) sin afectar la ubicación del resto. Como ejemplo, agreguemos un cheque por campos de entrada vacíos y, en caso de error, mostraremos un mensaje directamente debajo del campo vacío:
Y aunque el mensaje debe "integrarse" en el diseño existente, ¡ni siquiera necesita cambiar el código existente para esto!
func showErrorForField(_ field: UITextField) {
errorLabel.frame = field.convert(field.bounds, to: boxView)
let item = errorLabel.boxed.top(-boxView.spacing).left(errorLabel.frame.minX - boxView.insets.left)
boxView.insertItem(item, after: field.superview, z: .back)
boxView.animateChangesWithDurations(0.3)
}
@objc func onClickButton(sender: UIButton) {
for field in [nameField, passwordField] {
if field.text?.isEmpty ?? true {
showErrorForField(field)
return
}
}
// ok, can proceed with login
}
@objc func onChangeTextField(sender: UITextField) {
errorLabel.removeFromSuperview()
boxView.animateChangesWithDurations(0.3)
}
BoxView es compatible con todo el kit de herramientas de distribución automática: distancias entre elementos, tamaños absolutos y relativos, prioridades, soporte de lenguaje RTL. Además de UIView, los objetos invisibles - UILayoutGuides también se pueden usar como elementos de diseño. El diseño flexible también se puede utilizar. Por supuesto, el esquema de diseño en sí mismo, en forma de un sistema de pilas UIView anidadas, no cubre al 100% todas las opciones concebibles para la disposición relativa de los elementos, pero esto no es obligatorio. Está bien para la gran mayoría de las interfaces de usuario típicas, y para casos más exóticos, siempre puede agregar restricciones adicionales apropiadas de cualquier otra manera. Varios métodos de utilidad, por ejemplo, para crear restricciones de relación de aspecto, también se incluyen en la biblioteca.
Otro pequeño ejemplodisponible en github (¡~ 100 líneas de código!) ilustra el uso del sistema BoxView anidado junto con otros métodos de configuración de restricciones, así como cambios animados en los parámetros de BoxView.
Proyecto BoxView en github