ios xcode ios7 xcode5

ios - ¿Hay alguna forma de agregar restricciones entre una vista y la guía de diseño superior en un archivo xib?



xcode ios7 (7)

Aquí está mi solución alternativa.

Encuentre un UIView como pivote, establezca su restricción de diseño superior como un espacio vertical fijo en la parte superior del contenedor.

Control-Arrastre esta restricción de diseño como IBOutlet, como

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topLayoutConstraint;

Finalmente, simplemente anule el método viewWillLayoutSubviews de UIViewController como sigue

- (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; self.topLayoutConstraint.constant = [self.topLayoutGuide length] + YOUR_TOP_CONSTRSINT; }

Todas las demás restricciones de la vista se basan en esta vista dinámica, todo hecho :)

En iOS 7, ahora podemos agregar una restricción entre una vista y la guía de diseño superior, que creo que es muy útil para resolver el problema de compensación de la barra de estado en iOS7 (especialmente cuando no hay una barra de navegación en la vista).

En un archivo de guión gráfico, puedo agregar este tipo de restricciones fácilmente. Simplemente mantenga presionada la tecla control y luego arrastre la vista al contenedor, se mostrará la opción "Top Space to Top Layout Guide".

Pero cuando hago la misma operación en un archivo xib, esta opción desaparece.

Entonces, ¿hay alguna manera de agregar este tipo de restricciones en los archivos xib? ¿O tengo que agregarlos con el código?


Creo que la razón por la que no aparecen en el XIB es que no hay conocimiento de la jerarquía del controlador de vista en esa situación, mientras que en un story board IB puede decir dónde están las guías desde la jerarquía del controlador de vista en la que se encuentra la vista. Es decir, si está contenido en un UINavigationController, puede determinar que la guía de diseño superior se encuentre debajo de la barra de herramientas de navegación.


Debe consultar el siguiente ejemplo, esto definitivamente lo ayudará con su problema. Obtuve esto de http://developer.apple.com .

[button setTranslatesAutoresizingMaskIntoConstraints: NO]; id topGuide = myViewController.topLayoutGuide; NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings (button, topGuide); [myViewController.view addConstraints: [NSLayoutConstraint constraintsWithVisualFormat: @"V:[topGuide]-20-[button]" options: 0 metrics: nil views: viewsDictionary] ];


Desde iOS 9 también puedes hacerlo de manera más simple con los anchors de topLayoutGuide:

  • Swift 3

view.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor).isActive = true

  • ObjC

[controller.view.topAnchor constraintEqualToAnchor:controller.topLayoutGuide.bottomAnchor].active = YES;


Hasta ahora, incluso utilizando XCode 6 no puedo alinear los controles a la guía de diseño superior en archivos .xib. En cambio, estoy usando una forma alternativa.

En primer lugar, en el constructor de interfaces, sigo alineando los controles con el borde superior de la vista del controlador de vista.

Luego, en el método viewDidLoad, reemplazo algunas restricciones para que se alineen con la guía de diseño superior en lugar de la vista principal:

- (void)viewDidLoad { [super viewDidLoad]; NSArray *constraints = self.view.constraints; for (NSLayoutConstraint *constraint in constraints) { if ( (constraint.firstItem == self.view) && (constraint.firstAttribute == NSLayoutAttributeTop) ) { NSLayoutConstraint *newConstraint = [self constraint:constraint replaceFirstItemBy:self.topLayoutGuide attribute:NSLayoutAttributeBottom]; [self.view removeConstraint:constraint]; [self.view addConstraint:newConstraint]; } else if ( (constraint.secondItem == self.view) && (constraint.secondAttribute == NSLayoutAttributeTop) ) { NSLayoutConstraint *newConstraint = [self constraint:constraint replaceSecondItemBy:self.topLayoutGuide attribute:NSLayoutAttributeBottom]; [self.view removeConstraint:constraint]; [self.view addConstraint:newConstraint]; } } } - (NSLayoutConstraint*)constraint:(NSLayoutConstraint*)constraint replaceFirstItemBy:(id)newItem attribute:(NSLayoutAttribute)newAttribute { UILayoutPriority priority = constraint.priority; NSLayoutRelation relation = constraint.relation; id secondItem = constraint.secondItem; NSLayoutAttribute secondAttribute = constraint.secondAttribute; CGFloat multiplier = constraint.multiplier; CGFloat constant = constraint.constant; NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:newItem attribute:newAttribute relatedBy:relation toItem:secondItem attribute:secondAttribute multiplier:multiplier constant:constant]; newConstraint.priority = priority; return newConstraint; } - (NSLayoutConstraint*)constraint:(NSLayoutConstraint*)constraint replaceSecondItemBy:(id)newItem attribute:(NSLayoutAttribute)newAttribute { UILayoutPriority priority = constraint.priority; id firstItem = constraint.firstItem; NSLayoutAttribute firstAttribute = constraint.firstAttribute; NSLayoutRelation relation = constraint.relation; CGFloat multiplier = constraint.multiplier; CGFloat constant = constraint.constant; NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:firstItem attribute:firstAttribute relatedBy:relation toItem:newItem attribute:newAttribute multiplier:multiplier constant:constant]; newConstraint.priority = priority; return newConstraint; }

Piensa que esta no es la mejor manera porque reemplazamos los objetos que definimos en el constructor de interfaz. Pero puede ser una forma alternativa en la que podamos pensar.


La respuesta de Cao Huu Loc con swift 4

extension NSLayoutConstraint { func constraintReplacing(firstItemWith newFirstItem: UILayoutSupport, withAttribute newFirstAttribute: NSLayoutAttribute) -> NSLayoutConstraint { return NSLayoutConstraint(item: newFirstItem, attribute: newFirstAttribute, relatedBy: relation, toItem: secondItem, attribute: secondAttribute, multiplier: multiplier, constant: constant) } func constraintReplacing(secondItemWith newSecondItem: UILayoutSupport, withAttribute newSecondAttribute: NSLayoutAttribute) -> NSLayoutConstraint { return NSLayoutConstraint(item: firstItem as Any, attribute: firstAttribute, relatedBy: relation, toItem: newSecondItem, attribute: newSecondAttribute, multiplier: multiplier, constant: constant) } } class YourViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() for constraint in view.constraints { if constraint.firstItem === view && constraint.firstAttribute == .top { let newConstraint = constraint.constraintReplacing(firstItemWith: topLayoutGuide, withAttribute: .bottom) view.removeConstraint(constraint) view.addConstraint(newConstraint) } if constraint.secondItem === view && constraint.secondAttribute == .top { let newConstraint = constraint.constraintReplacing(secondItemWith: topLayoutGuide, withAttribute: .bottom) view.removeConstraint(constraint) view.addConstraint(newConstraint) } } } }


Por supuesto, no solo puede agregar restricción entre una vista y la top layout guide o la top layout guide bottom layout guide mediante programación, sino que también puede eliminar y acceder a la restricción entre una vista y la top and bottom layout guide con la ayuda de la biblioteca KVConstraintExtensionsMaster .

// create containerView UIView *containerView = [UIView prepareNewViewForAutoLayout]; [containerView setBackgroundColor:[UIColor brownColor]]; [self.view addSubview:containerView]; // To add Top and Bottom Layout Guide constraint of containerView [self applyTopLayoutGuideConstraintToView:containerView withPadding:0]; [self applyBottomLayoutGuideConstraintToView:containerView withPadding:50]; // To access top Layout Guide Constraint and update it''s constant value. NSLayoutConstraint *topLayoutGuideConstraint = [self accessAppliedTopLayoutGuideConstraintFromView:containerView]; topLayoutGuideConstraint.constant = 50; // To access bottom Layout Guide Constraint and update it''s constant value with animation NSLayoutConstraint *bottomLayoutGuideConstraint = [self accessAppliedBottomLayoutGuideConstraintFromView:containerView]; bottomLayoutGuideConstraint.constant = 80; [self.view updateModifyConstraintsWithAnimation:NULL]; // call this for animation // To remove Top and Bottom Layout Guide constraint of containerView [self removeAppliedTopLayoutGuideConstraintFromView:containerView]; [self removeAppliedBottomLayoutGuideConstraintFromView:containerView ];