restricciones olvide intentos fallidos eliminar desactivar como codigo borrar activar ios xcode swift autolayout nslayoutconstraint

ios - olvide - Agregar mediante programación las restricciones CenterX/CenterY



olvide mi codigo de restricciones iphone 5 (7)

Tengo un UITableViewController que no muestra ninguna sección si no hay nada que mostrar. Agregué una etiqueta para indicarle al usuario que no hay nada que mostrar con este código:

label = UILabel(frame: CGRectMake(20, 20, 250, 100)) label.text = "Nothing to show" self.tableView.addSubview(label)

Pero ahora, quiero que esté centrado horizontal y verticalmente. Normalmente, elegiría las dos opciones resaltadas (más las de altura y anchura) en la captura de pantalla:

He intentado el siguiente código para agregar las restricciones, pero la aplicación se bloquea con un error:

label = UILabel(frame: CGRectMake(20, 20, 250, 100)) label.text = "Nothing to show" let xConstraint = NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterX, multiplier: 1, constant: 0) let yConstraint = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterY, multiplier: 1, constant: 0) label.addConstraint(xConstraint) label.addConstraint(yConstraint)

error:

When added to a view, the constraint''s items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug. 2014-12-23 08:17:36.755 [982:227877] *** Assertion failure in -[UILabel _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:], /SourceCache/UIKit/UIKit-3318.16.21/NSLayoutConstraint_UIKitAdditions.m:560

La etiqueta siempre debe centrarse horizontal y verticalmente porque la aplicación admite la rotación del dispositivo.

¿Qué estoy haciendo mal? ¿Cómo agrego estas restricciones con éxito?

¡Gracias!


Centro en contenedor

El siguiente código hace lo mismo que centrarse en Interface Builder.

override func viewDidLoad() { super.viewDidLoad() // set up the view let myView = UIView() myView.backgroundColor = UIColor.blue myView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(myView) // Add code for one of the constraint methods below // ... }

Método 1: estilo de anclaje

myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

Método 2: NSLayoutConstraint Style

NSLayoutConstraint(item: myView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0).isActive = true NSLayoutConstraint(item: myView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0).isActive = true

Notas

  • El estilo de anclaje es el método preferido sobre NSLayoutConstraint Style, sin embargo, solo está disponible desde iOS 9, por lo que si es compatible con iOS 8, aún debe usar NSLayoutConstraint Style.
  • También necesitará agregar restricciones de longitud y ancho.
  • Mi respuesta completa está here .

El equivalente de ObjectiveC es:

myView.translatesAutoresizingMaskIntoConstraints = NO; [[myView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor] setActive:YES]; [[myView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor] setActive:YES];


En Swift 5 se ve así:

let horizontalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: parentView, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0) parentView.addConstraint(horizontalConstraint) let verticalConstraint = NSLayoutConstraint(item: newView, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: parentView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0) parentView.addConstraint(verticalConstraint)


Programáticamente puede hacerlo agregando las siguientes restricciones.

NSLayoutConstraint *constraintHorizontal = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:attribute multiplier:1.0f constant:0.0f]; NSLayoutConstraint *constraintVertical = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:attribute multiplier:1.0f constant:0.0f];


Si no le importa que esta pregunta sea específicamente sobre una vista de tabla, y simplemente desea centrar una vista encima de otra vista, aquí está:

label.translatesAutoresizingMaskIntoConstraints = false label.centerXAnchor.constraint(equalTo: vc.view.centerXAnchor).isActive = true label.centerYAnchor.constraint(equalTo: vc.view.centerYAnchor).isActive = true


Una solución para mí fue crear un UILabel y agregarlo al UIButton como una subvista. Finalmente agregué una restricción para centrarlo dentro del botón.

UILabel * myTextLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 75, 75)]; myTextLabel.text = @"Some Text"; myTextLabel.translatesAutoresizingMaskIntoConstraints = false; [myButton addSubView:myTextLabel]; // Add Constraints [[myTextLabel centerYAnchor] constraintEqualToAnchor:myButton.centerYAnchor].active = true; [[myTextLabel centerXAnchor] constraintEqualToAnchor:myButton.centerXAnchor].active = true;


Actualización para Swift 3 / Swift 4:

A partir de iOS 8, puede y debe activar sus restricciones estableciendo su propiedad isActive en true . Esto permite que las restricciones se agreguen a las vistas adecuadas. Puede activar varias restricciones a la vez pasando una matriz que contiene las restricciones a NSLayoutConstraint.activate()

let label = UILabel(frame: CGRect.zero) label.text = "Nothing to show" label.textAlignment = .center label.backgroundColor = .red // Set background color to see if label is centered label.translatesAutoresizingMaskIntoConstraints = false self.tableView.addSubview(label) let widthConstraint = NSLayoutConstraint(item: label, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 250) let heightConstraint = NSLayoutConstraint(item: label, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100) let xConstraint = NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: self.tableView, attribute: .centerX, multiplier: 1, constant: 0) let yConstraint = NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: self.tableView, attribute: .centerY, multiplier: 1, constant: 0) NSLayoutConstraint.activate([widthConstraint, heightConstraint, xConstraint, yConstraint])

Mejor solución

Dado que esta pregunta se respondió originalmente, se introdujeron los anclajes de diseño, lo que facilita mucho la creación de restricciones. En este ejemplo, creo las restricciones y las activo de inmediato:

label.widthAnchor.constraint(equalToConstant: 250).isActive = true label.heightAnchor.constraint(equalToConstant: 100).isActive = true label.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor).isActive = true label.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor).isActive = true

o lo mismo usando NSLayoutConstraint.activate() :

NSLayoutConstraint.activate([ label.widthAnchor.constraint(equalToConstant: 250), label.heightAnchor.constraint(equalToConstant: 100), label.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor), label.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor) ])

Nota: Agregue siempre sus subvistas a la jerarquía de vistas antes de crear y activar las restricciones.

Respuesta original

Las restricciones hacen referencia a self.tableView . Como está agregando la etiqueta como una subvista de self.tableView , las restricciones deben agregarse al "ancestro común":

self.tableView.addConstraint(xConstraint) self.tableView.addConstraint(yConstraint)

Como @mustafa y @kcstricks señalaron en los comentarios, debe establecer label.translatesAutoresizingMaskIntoConstraints en false . Cuando hace esto, también necesita especificar el width y el height de la etiqueta con restricciones porque el marco ya no se usa. Finalmente, también debe establecer textAlignment en .Center para que su texto esté centrado en su etiqueta.

var label = UILabel(frame: CGRectZero) label.text = "Nothing to show" label.textAlignment = .Center label.backgroundColor = UIColor.redColor() // Set background color to see if label is centered label.translatesAutoresizingMaskIntoConstraints = false self.tableView.addSubview(label) let widthConstraint = NSLayoutConstraint(item: label, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 250) label.addConstraint(widthConstraint) let heightConstraint = NSLayoutConstraint(item: label, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 100) label.addConstraint(heightConstraint) let xConstraint = NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterX, multiplier: 1, constant: 0) let yConstraint = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterY, multiplier: 1, constant: 0) self.tableView.addConstraint(xConstraint) self.tableView.addConstraint(yConstraint)