Restricciones de diseño mediante programación en Xamarin.iOS

En esta guía se presenta cómo trabajar con restricciones de diseño automático de iOS en código de C# en lugar de crearlas en iOS Designer

El diseño automático (también denominado "diseño adaptativo") es un enfoque de diseño dinámico. A diferencia del sistema de diseño de transición, donde la ubicación de cada elemento está codificada de forma rígida hasta un punto en la pantalla, el diseño automático trata sobre las relaciones: las posiciones de los elementos en relación con otros elementos en la superficie de diseño. En el corazón del diseño automático se encuentra la idea de restricciones o reglas que definen la colocación de un elemento o conjunto de elementos en el contexto de otros elementos en la pantalla. Dado que los elementos no están vinculados a una posición determinada en la pantalla, las restricciones ayudan a crear un diseño adaptativo que se ve bien en diferentes tamaños de pantalla y orientaciones de dispositivos.

Normalmente, al trabajar con el diseño automático en iOS, usará Interface Builder de Xcode para colocar gráficamente restricciones de diseño en los elementos de la interfaz de usuario. Sin embargo, puede haber ocasiones en las que sea necesario crear y aplicar restricciones en el código de C#. Por ejemplo, cuando se usan elementos de la interfaz de usuario creados dinámicamente agregados a un UIView.

Esta guía le mostrará cómo crear y trabajar con restricciones mediante código de C# en lugar de crearlas gráficamente en Interface Builder de Xcode.

Creación de restricciones mediante programación

Como se ha indicado anteriormente, normalmente trabajará con restricciones de diseño automático en iOS Designer. Para aquellas ocasiones en las que tenga que crear las restricciones mediante programación, cuenta con tres opciones entre las que elegir:

  • Delimitadores de diseño: esta API proporciona acceso a las propiedades de delimitador (como TopAnchor, BottomAnchor o HeightAnchor) de los elementos de la interfaz de usuario que se restringen.
  • Restricciones de diseño: puede crear restricciones directamente mediante la clase NSLayoutConstraint.
  • Lenguaje de formato visual: proporciona un método similar a una imagen ASCII para definir las restricciones.

En las secciones siguientes, se describe cada opción con detalle.

Delimitadores de diseño

Mediante el uso de la clase NSLayoutAnchor, tiene una interfaz fluida para crear restricciones en función de las propiedades de delimitador de los elementos de la interfaz de usuario que se restringen. Por ejemplo, las guías de diseño superior e inferior de un controlador de vista exponen las propiedades de delimitador TopAnchor, BottomAnchor y HeightAnchor, mientras que una vista expone las propiedades de borde, centro, tamaño y línea de base.

Importante

Además del conjunto estándar de propiedades de delimitador, las vistas de iOS también incluyen las propiedades LayoutMarginsGuides y ReadableContentGuide. Estas propiedades exponen objetos UILayoutGuide para trabajar con los márgenes de la vista y las guías de contenido legibles, respectivamente.

Los delimitadores de diseño proporcionan varios métodos para crear restricciones en un formato fácil de leer y compacto:

  • ConstraintEqualTo: define una relación donde first attribute = second attribute + [constant] con un valor de desplazamiento constant proporcionado opcionalmente.
  • ConstraintGreaterThanOrEqualTo: define una relación donde first attribute >= second attribute + [constant] con un valor de desplazamiento constant proporcionado opcionalmente.
  • ConstraintLessThanOrEqualTo: define una relación donde first attribute <= second attribute + [constant] con un valor de desplazamiento constant proporcionado opcionalmente.

Por ejemplo:

// Get the parent view's layout
var margins = View.LayoutMarginsGuide;

// Pin the leading edge of the view to the margin
OrangeView.LeadingAnchor.ConstraintEqualTo (margins.LeadingAnchor).Active = true;

// Pin the trailing edge of the view to the margin
OrangeView.TrailingAnchor.ConstraintEqualTo (margins.TrailingAnchor).Active = true;

// Give the view a 1:2 aspect ratio
OrangeView.HeightAnchor.ConstraintEqualTo (OrangeView.WidthAnchor, 2.0f);

Una restricción de diseño típica se puede expresar simplemente como una expresión lineal. Considere el ejemplo siguiente:

A Layout Constraint expressed as a linear expression

Que se convertiría en la siguiente línea de código de C# mediante delimitadores de diseño:

PurpleView.LeadingAnchor.ConstraintEqualTo (OrangeView.TrailingAnchor, 10).Active = true; 

Donde los elementos del código de C# corresponden a los elementos especificados de la ecuación de la siguiente manera:

Ecuación Código
Elemento 1 PurpleView
Atributo 1 LeadingAnchor
Relación ConstraintEqualTo
Multiplicador Su valor predeterminado es 1.0, por lo que no se especifica
Elemento 2 OrangeView
Atributo 2 TrailingAnchor
Constante 10.0

Además de proporcionar solo los parámetros necesarios para resolver una ecuación de restricción de diseño determinada, cada uno de los métodos de delimitador de diseño aplica la seguridad de tipo de los parámetros que se les pasan. Por lo tanto, los delimitadores de restricciones horizontales (como LeadingAnchor o TrailingAnchor) solo se pueden usar con otros tipos de delimitadores horizontales y solo se proporcionan multiplicadores para restricciones de tamaño.

Restricciones de diseño

Puede agregar restricciones de diseño automático manualmente mediante la construcción directa de una NSLayoutConstraint en el código de C#. A diferencia de utilizar delimitadores de diseño, debe especificar un valor para todos los parámetros, incluso si va a tener ningún efecto en la restricción que se define. Como resultado, terminará produciendo una cantidad considerable de código reutilizable difícil de leer. Por ejemplo:

//// Pin the leading edge of the view to the margin
NSLayoutConstraint.Create (OrangeView, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, View, NSLayoutAttribute.LeadingMargin, 1.0f, 0.0f).Active = true;

//// Pin the trailing edge of the view to the margin
NSLayoutConstraint.Create (OrangeView, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, View, NSLayoutAttribute.TrailingMargin, 1.0f, 0.0f).Active = true;

//// Give the view a 1:2 aspect ratio
NSLayoutConstraint.Create (OrangeView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, OrangeView, NSLayoutAttribute.Width, 2.0f, 0.0f).Active = true;

Donde la enumeración NSLayoutAttribute define el valor de los márgenes de la vista y corresponde a las propiedades LayoutMarginsGuide (como Left, Right, Top y Bottom) y la enumeración NSLayoutRelation define la relación que se va a crear entre los atributos especificados como Equal, LessThanOrEqual o GreaterThanOrEqual.

A diferencia de la API de delimitador de diseño, los métodos de creación NSLayoutConstraint no resaltan los aspectos importantes de una restricción determinada y no se realizan comprobaciones en tiempo de compilación en la restricción. Como resultado, es fácil construir una restricción no válida que inicie una excepción en tiempo de ejecución.

Lenguaje de formato visual

El lenguaje de formato visual permite definir restricciones mediante cadenas similares a una imagen ASCII que proporcionan una representación visual de la restricción que se crea. Esto tiene estas ventajas y desventajas:

  • El lenguaje de formato visual solo exige la creación de restricciones válidas.
  • El diseño automático genera restricciones en la consola mediante el lenguaje de formato visual para que los mensajes de depuración sean similares al código usado para crear la restricción.
  • El lenguaje de formato visual permite crear varias restricciones al mismo tiempo con una expresión muy compacta.
  • Puesto que no hay ninguna validación del lado de compilación de las cadenas de lenguaje de formato visual, los problemas solo se pueden detectar en tiempo de ejecución.
  • Dado que el lenguaje de formato visual resalta la visualización sobre la integridad, algunos tipos de restricciones no se pueden crear con él (como las relaciones).

Siga estos pasos al usar el lenguaje de formato visual para crear una restricción:

  1. Cree un NSDictionary que contenga los objetos de vista y Guías de diseño y una clave de cadena que se usará al definir los formatos.
  2. Opcionalmente, cree un NSDictionary que defina un conjunto de claves y valores (NSNumber) usados como valor constante de la restricción.
  3. Cree la cadena de formato para diseñar una sola columna o fila de elementos.
  4. Llame al método FromVisualFormat de la clase NSLayoutConstraint para generar las restricciones.
  5. Llame al método ActivateConstraints de la clase NSLayoutConstraint para activar y aplicar las restricciones.

Por ejemplo, para crear una restricción inicial y una restricción final en el lenguaje de formato visual, puede usar lo siguiente:

// Get views being constrained
var views = new NSMutableDictionary (); 
views.Add (new NSString ("orangeView"), OrangeView);

// Define format and assemble constraints
var format = "|-[orangeView]-|";
var constraints = NSLayoutConstraint.FromVisualFormat (format, NSLayoutFormatOptions.AlignAllTop, null, views);

// Apply constraints
NSLayoutConstraint.ActivateConstraints (constraints);

Dado que el lenguaje de formato visual siempre crea restricciones de punto cero asociadas a los márgenes de la vista primaria al usar el espaciado predeterminado, este código genera resultados idénticos a los ejemplos presentados anteriormente.

Para diseños de interfaz de usuario más complejos, como varias vistas secundarias en una sola línea, el lenguaje de formato visual especifica tanto el espaciado horizontal como la alineación vertical. Como en el ejemplo anterior donde especifica AlignAllTop, NSLayoutFormatOptions alinea todas las vistas de una fila o columna con sus partes superiores.

Consulte el Apéndice del lenguaje de formato visual de Apple para ver algunos ejemplos de cómo especificar restricciones comunes y la gramática de cadenas de formato visual.

Resumen

En esta guía se ha presentado cómo crear y trabajar con restricciones de diseño automático en C# en lugar de crearlas gráficamente en iOS Designer. En primer lugar, se ha examinado el uso de delimitadores de diseño (NSLayoutAnchor) para controlar el diseño automático. A continuación, se mostró cómo trabajar con delimitadores de diseño (NSLayoutConstraint). Por último, se ha presentado mediante el lenguaje de formato visual para el diseño automático.