Crear restricciones de diseño mediante programación

84

Sé que mucha gente ya hizo muchas preguntas sobre esto, pero incluso con las respuestas no puedo hacer que funcione.

Cuando estoy lidiando con restricciones en el guión gráfico, es fácil, pero en el código lo tengo difícil. Intento, por ejemplo, tener una vista que se quede en el lado derecho y tenga la altura de la pantalla según la orientación de la pantalla. Este es mi codigo:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

No satisface algunas limitaciones. No veo lo que está mal. Además, ¿por qué no puedo usar una propiedad como en self.myViewlugar de una variable local como myView?

pierre23
fuente
¿Qué es vivi en el código anterior?
iDev
14
Cambie el título a "iOS" en lugar de "IOS". Este último se refiere al sistema operativo de conmutador / enrutador de Cisco. Me confundió. Gracias.
armani
1
Varias preguntas sobre esto: (1) ¿Qué error está obteniendo cuando "no satisface algunas restricciones"? (2) ¿Está traduciendo la conversión automática en restricciones myView? (3) ¿Qué es vivi(como preguntó ACB)? (4) ¿Tiene una propiedad myViewdeclarada self?
Tim
1
ih Tim, perdón por el vivi, hice tapping demasiado rápido ... es myView. ¿A qué te refieres con traducir? Todo lo que hago está en el código de arriba. Acerca de la propiedad, tengo algunas otras vistas que se declaran como propiedad, pero cuando implemento el mismo código en esas propiedades, se bloquea ... el mensaje "error" es realmente grande, no puedo pegarlo aquí
pierre23
Para eliminar las restricciones de una vista en particular temporalmente, haga esto stackoverflow.com/questions/13388104/…
Sam B

Respuestas:

106

Cuando se usa el diseño automático en el código, configurar el marco no hace nada. Por lo tanto, el hecho de que haya especificado un ancho de 200 en la vista anterior no significa nada cuando le establece restricciones. Para que el conjunto de restricciones de una vista no sea ambiguo, necesita cuatro cosas: una posición x, una posición y, un ancho y una altura para cualquier estado dado.

Actualmente, en el código anterior, solo tiene dos (altura, relativa a la supervista, y posición y, relativa a la supervista). Además de esto, tiene dos restricciones requeridas que podrían entrar en conflicto dependiendo de cómo se configuren las restricciones de la supervista de la vista. Si la supervista tuviera una restricción requerida que especifique que su altura debe tener un valor menor que 748, obtendrá una excepción de "restricciones insatisfactorias".

El hecho de que haya establecido el ancho de la vista antes de establecer restricciones no significa nada. Ni siquiera tendrá en cuenta el marco anterior y calculará un marco nuevo en función de todas las restricciones que ha especificado para esas vistas. Cuando trato con el diseño automático en el código, normalmente solo creo una nueva vista usando initWithFrame:CGRectZeroo simplemente init.

Para crear el conjunto de restricciones requerido para el diseño que describió verbalmente en su pregunta, necesitaría agregar algunas restricciones horizontales para delimitar el ancho y la posición x para dar un diseño completamente especificado:

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"H:[myView(==200)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

La descripción verbal de este diseño es la siguiente, comenzando con la restricción vertical:

myView llenará la altura de su supervista con un relleno superior e inferior igual al espacio estándar. La supervista de myView tiene una altura mínima de 748pts. El ancho de myView es 200pts y tiene un relleno derecho igual al espacio estándar contra su supervista.

Si simplemente desea que la vista llene la altura de la supervista completa sin restringir la altura de la supervista, entonces simplemente omitiría el (>=748)parámetro en el texto del formato visual. Si cree que el (>=748)parámetro es necesario para darle una altura, no lo hace en este caso: anclar la vista a los bordes de la supervista usando la barra ( |) o la barra con espacio ( |-,-| sintaxis de ), está dando su vista a y -posición (fijar la vista en un solo borde) y una posición y con altura (fijar la vista en ambos bordes), satisfaciendo así su conjunto de restricciones para la vista.

En cuanto a su segunda pregunta:

Utilizando NSDictionaryOfVariableBindings(self.myView)(si tuviera una configuración de propiedad para myView) y la alimentación que en su VFL a utilizar self.myViewen el texto VFL, es probable que obtener una excepción cuando autolayout intenta analizar el texto VFL. Tiene que ver con la notación de puntos en las claves del diccionario y el sistema que intenta usar valueForKeyPath:. Vea aquí una pregunta y una respuesta similares .

larsacus
fuente
No olvide que algunos objetos como UILabel tienen un tamaño intrínseco y no tiene que establecer el ancho o alto de ese objeto, solo su posición. Sin embargo, si establece la altura o el ancho, creo que elimina ambos y luego debe proporcionar ambos.
Nick Turner
Aunque esta respuesta no respondió a mi pregunta, me ayudó a darme cuenta de algo. ¡Gracias por ser! :)
Matej
1
La única introducción de diseño automático concisa y legible en Internet hasta ahora.
Joey Carson
por
61

Hola, he estado usando mucho esta página para conocer las limitaciones y el "cómo". Me tomó una eternidad llegar al punto de darme cuenta de que necesitaba:

myView.translatesAutoresizingMaskIntoConstraints = NO;

para que este ejemplo funcione. Gracias Userxxx, Rob M. y especialmente larsacus por la explicación y el código aquí, ha sido invaluable.

Aquí está el código completo para ejecutar los ejemplos anteriores:

UIView *myView = [[UIView alloc] init];
myView.backgroundColor = [UIColor redColor];
myView.translatesAutoresizingMaskIntoConstraints = NO;  //This part hung me up 
[self.view addSubview:myView];
//needed to make smaller for iPhone 4 dev here, so >=200 instead of 748
[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:[myView(==200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];
BriOnH
fuente
11

Versión rápida

Actualizado para Swift 3

Este ejemplo mostrará dos métodos para agregar mediante programación las siguientes restricciones de la misma manera que si lo hiciera en Interface Builder:

Anchura y altura

ingrese la descripción de la imagen aquí

Centro en contenedor

ingrese la descripción de la imagen aquí

Código repetitivo

override func viewDidLoad() {
    super.viewDidLoad()

    // set up the view
    let myView = UIView()
    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    // Add constraints code here (choose one of the methods below)
    // ...
}

Método 1: estilo de ancla

// width and height
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

// center in container
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

Método 2: Estilo NSLayoutConstraint

// width and height
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true

// center in container
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true

Notas

  • El estilo de anclaje es el método preferido sobre el NSLayoutConstraintestilo, sin embargo, solo está disponible en iOS 9, por lo que si es compatible con iOS 8, debe usar NSLayoutConstraintStyle.
  • Consulte también la documentación de Creación de restricciones mediante programación .
  • Consulte esta respuesta para ver un ejemplo similar de cómo agregar una restricción de fijación.
Suragch
fuente
5

Con respecto a su segunda pregunta sobre propiedades, puede usar self.myViewsolo si la declaró como propiedad en la clase. Dado que myViewes una variable local, no puede usarla de esa manera. Para obtener más detalles sobre esto, le recomendaría que consulte la documentación de Apple sobre Propiedades declaradas ,

iDev
fuente
5

¿Por qué no puedo usar una propiedad como en self.myViewlugar de una variable local como myView?

intente usar:

NSDictionaryOfVariableBindings(_view)

en vez de self.view

Megarushing
fuente
Eso hace que mi aplicación se bloquee, da un mensaje: 'No se puede analizar el formato de restricción: polylineImageView no es una clave en el diccionario de vistas'.
Tai Le
4

Tenga en cuenta también que desde iOS9 podemos definir restricciones mediante programación "más concisas y más fáciles de leer" utilizando subclases de la nueva clase auxiliar NSLayoutAnchor .

Un ejemplo del documento:

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
andreacipriani
fuente