Creación de restricciones de diseño mediante programación


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

Cuando estoy lidiando con restricciones en storyboard, es fácil, pero en código lo paso mal. Intento, por ejemplo, tener una vista que permanezca en el lado derecho y tenga la altura de la pantalla de acuerdo con la orientación de la pantalla. Este es mi código:

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 restricciones. No veo qué está mal. Además, ¿por qué no puedo usar una propiedad como self.myView en lugar de una variable local como myView?

Author: pierre23, 2012-10-10

6 answers

Cuando se utiliza el Diseño automático en el código, establecer el marco no hace nada. Así que el hecho de que haya especificado un ancho de 200 en la vista anterior, no significa nada cuando se establecen restricciones en ella. Para que el conjunto de restricciones de una vista sea inequívoco, 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 (height, relativo al superview, y y-position, relativo al superview). Además de esto, tiene dos restricciones requeridas que podrían entrar en conflicto dependiendo de cómo se configuran las restricciones de superview de la vista. Si el superview tuviera una restricción requerida que especifique que su altura sea 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 antiguo y calculará un nuevo marco basado en todos the constraints that it has specified for those views. Cuando se trata de autoayout en código, normalmente solo creo una nueva vista usando initWithFrame:CGRectZero o simplemente init.

Para crear el conjunto de restricciones requerido para el diseño que describió verbalmente en su pregunta, debería agregar algunas restricciones horizontales para vincular el ancho y la posición x con el fin de 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 se lee de la siguiente manera, comenzando con la vertical restricción:

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

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

Con respecto a su segunda pregunta:

Usando NSDictionaryOfVariableBindings(self.myView) (si tiene una propiedad configuración para MyView) y alimentando eso en su VFL para usar self.myView en su texto VFL, probablemente obtendrá una excepción cuando autolayout intente analizar su 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 respuesta similar.

 105
Author: larsacus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:09:40

Hola he estado usando esta página mucho para restricciones y "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)]];
 61
Author: BriOnH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-13 02:45:44

Versión Swift

Actualizado para Swift 3

Este ejemplo mostrará dos métodos para agregar programáticamente las siguientes restricciones igual que si lo hiciera en el Creador de interfaces:

Anchura y altura

introduzca la descripción de la imagen aquí

Centro en el Contenedor

introduzca 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 anclaje

// 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: NSLayoutConstraint Estilo

// 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 Estilo NSLayoutConstraint, sin embargo, solo está disponible desde iOS 9, por lo que si admite iOS 8, aún debe usar el estilo NSLayoutConstraint.
  • Vea también la documentación Creando Restricciones mediante programación.
  • Vea esta respuesta para un ejemplo similar de agregar una restricción de fijación.
 10
Author: Suragch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:17:44

Con respecto a su segunda pregunta sobre propiedades, puede usar self.myView solo si la declaró como una propiedad en clase. Dado que myView es una variable local, no puede usarla de esa manera. Para más detalles sobre esto, le recomiendo que revise la documentación de apple sobre Propiedades declaradas ,

 5
Author: iDev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-10 23:04:37

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

Intenta usar:

NSDictionaryOfVariableBindings(_view)

En Lugar de self.view

 5
Author: Megarushing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-22 05:58:33

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

Un ejemplo del doc:

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
 4
Author: andreacipriani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-23 14:29:00