topanchor programmatic create constraint code ios iphone objective-c nslayoutconstraint

ios - programmatic - ¿Puedo cambiar la propiedad del multiplicador para NSLayoutConstraint?



programmatically constraints swift 4 (9)

Aquí hay una extensión NSLayoutConstraint en Swift que hace que establecer un nuevo multiplicador sea bastante fácil:

import Foundation import UIKit extension NSLayoutConstraint { func setMultiplier(multiplier:CGFloat) -> NSLayoutConstraint { NSLayoutConstraint.deactivateConstraints([self]) let newConstraint = NSLayoutConstraint( item: firstItem, attribute: firstAttribute, relatedBy: relation, toItem: secondItem, attribute: secondAttribute, multiplier: multiplier, constant: constant) newConstraint.priority = priority newConstraint.shouldBeArchived = shouldBeArchived newConstraint.identifier = identifier NSLayoutConstraint.activateConstraints([newConstraint]) return newConstraint } }

En Swift 3.0

import Foundation import UIKit extension NSLayoutConstraint { /** Change multiplier constraint - parameter multiplier: CGFloat - returns: NSLayoutConstraint */ func setMultiplier(multiplier:CGFloat) -> NSLayoutConstraint { NSLayoutConstraint.deactivate([self]) let newConstraint = NSLayoutConstraint( item: firstItem, attribute: firstAttribute, relatedBy: relation, toItem: secondItem, attribute: secondAttribute, multiplier: multiplier, constant: constant) newConstraint.priority = priority newConstraint.shouldBeArchived = self.shouldBeArchived newConstraint.identifier = self.identifier NSLayoutConstraint.activate([newConstraint]) return newConstraint } }

Uso de demostración:

@IBOutlet weak var myDemoConstraint:NSLayoutConstraint! override func viewDidLoad() { let newMultiplier:CGFloat = 0.80 myDemoConstraint = myDemoConstraint.setMultiplier(newMultiplier) //If later in view lifecycle, you may need to call view.layoutIfNeeded() }

Creé dos vistas en una supervista y luego agregué restricciones entre las vistas:

_indicatorConstrainWidth = [NSLayoutConstraint constraintWithItem:self.view1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view2 attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f]; [_indicatorConstrainWidth setPriority:UILayoutPriorityDefaultLow]; _indicatorConstrainHeight = [NSLayoutConstraint constraintWithItem:self.view1 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view2 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]; [_indicatorConstrainHeight setPriority:UILayoutPriorityDefaultLow]; [self addConstraint:_indicatorConstrainWidth]; [self addConstraint:_indicatorConstrainHeight];

Ahora quiero cambiar la propiedad del multiplicador por animación, pero no puedo descifrar cómo cambiar la propiedad del multiplicador. (Encontré _coefficient en propiedad privada en el archivo de encabezado NSLayoutConstraint.h, pero es privado.)

¿Cómo cambio la propiedad de multiplicador?

Mi solución es eliminar la restricción anterior y agregar la nueva con un valor diferente para el multipler .


Aquí hay una respuesta basada en la respuesta de @ Tianfu en C #. Otras respuestas que requieren activación y desactivación de restricciones no funcionaron para mí.

var isMapZoomed = false @IBAction func didTapMapZoom(_ sender: UIButton) { let offset = -1.0*graphHeightConstraint.secondItem!.frame.height*(1.0 - graphHeightConstraint.multiplier) graphHeightConstraint.constant = (isMapZoomed) ? offset : 0.0 isMapZoomed = !isMapZoomed self.view.layoutIfNeeded() }


En cambio, puede cambiar la propiedad "constante" para lograr el mismo objetivo con un poco de matemática. Suponga que su multiplicador predeterminado en la restricción es 1.0f. Este es el código Xamarin C # que se puede traducir fácilmente a objetivo-c

private void SetMultiplier(nfloat multiplier) { FirstItemWidthConstraint.Constant = -secondItem.Frame.Width * (1.0f - multiplier); }


La propiedad del multiplier es de solo lectura. Debe eliminar la antigua NSLayoutConstraint y reemplazarla por una nueva para modificarla.

Sin embargo, como sabes que quieres cambiar el multiplicador, puedes cambiar la constante multiplicándola tú mismo cuando se necesiten cambios, que a menudo es menos código.


Si solo tiene que aplicar dos conjuntos de multiplicadores, desde iOS8 en adelante puede agregar ambos conjuntos de restricciones y decidir cuál debería estar activo en cualquier momento:

NSLayoutConstraint *standardConstraint, *zoomedConstraint; // ... // switch between constraints standardConstraint.active = NO; // this line should always be the first line. because you have to deactivate one before activating the other one. or they will conflict. zoomedConstraint.active = YES; [self.view layoutIfNeeded]; // or using [UIView animate ...]


Una función auxiliar que uso para cambiar el multiplicador de una restricción de diseño existente. Crea y activa una nueva restricción y desactiva la anterior.

struct MyConstraint { static func changeMultiplier(_ constraint: NSLayoutConstraint, multiplier: CGFloat) -> NSLayoutConstraint { let newConstraint = NSLayoutConstraint( item: constraint.firstItem, attribute: constraint.firstAttribute, relatedBy: constraint.relation, toItem: constraint.secondItem, attribute: constraint.secondAttribute, multiplier: multiplier, constant: constraint.constant) newConstraint.priority = constraint.priority NSLayoutConstraint.deactivate([constraint]) NSLayoutConstraint.activate([newConstraint]) return newConstraint } }

Uso, cambiando el multiplicador a 1.2:

constraint = MyConstraint.changeMultiplier(constraint, multiplier: 1.2)


Uno puede leer:

var multiplier: CGFloat The multiplier applied to the second attribute participating in the constraint.

en esta página de documentación . ¿Eso no significa que uno debería poder modificar el multiplicador (ya que es una var)?


Versión de Objective-C para Andrew Schreiber respuesta

Cree la categoría para NSLayoutConstraint Class y agregue el método en un archivo .h como este

#import <UIKit/UIKit.h> @interface NSLayoutConstraint (Multiplier) -(instancetype)updateMultiplier:(CGFloat)multiplier; @end

En el archivo .m

#import "NSLayoutConstraint+Multiplier.h" @implementation NSLayoutConstraint (Multiplier) -(instancetype)updateMultiplier:(CGFloat)multiplier { [NSLayoutConstraint deactivateConstraints:[NSArray arrayWithObjects:self, nil]]; NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:self.firstItem attribute:self.firstAttribute relatedBy:self.relation toItem:self.secondItem attribute:self.secondAttribute multiplier:multiplier constant:self.constant]; [newConstraint setPriority:self.priority]; newConstraint.shouldBeArchived = self.shouldBeArchived; newConstraint.identifier = self.identifier; newConstraint.active = true; [NSLayoutConstraint activateConstraints:[NSArray arrayWithObjects:newConstraint, nil]]; //NSLayoutConstraint.activateConstraints([newConstraint]) return newConstraint; } @end

Más adelante en ViewController crea la salida para la restricción que deseas actualizar.

@property (strong, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;

y actualiza el multiplicador donde quieras, como a continuación ...

self.topConstraint = [self.topConstraint updateMultiplier:0.9099];


supongamos que una vista1 en el guión gráfico tiene una restricción de ancho para la vista principal (auto.vista en código) como esta

view1Width = view * 0.7 + constant

en lugar de crear 2 restricciones y cambiar entre ellas cambiando la propiedad activa ORRR [desactivando la restricción actual con el multiplicador anterior y creando una nueva con un nuevo multiplicador] déjala 1 restricción y juega con su constante

supongamos que quiero cambiar el multiplicador de view1 a 0.9 en lugar de 0.7

Puedo hacer esto

self.view1Width.constant += self.view.frame.size.width * 0.2

lo mismo que haces para restar