¿Puedo cambiar la propiedad multiplicadora para NSLayoutConstraint?

Creé dos vistas en una supervisión 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 multiplicadora con animation, pero no puedo entender cómo cambiar la propiedad multiplicador. (Encontré _coefficient en propiedad privada en el file de encabezado NSLayoutConstraint.h, pero es privado.)

¿Cómo cambio la propiedad multiplicador?

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

Si solo tiene dos sets de multiplicadores que deben aplicarse, a partir de iOS8 puede agregar ambos sets de restricciones y decidir cuál debe 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 ...] 

Aquí hay una extensión NSLayoutConstraint en Swift que hace que configurar un nuevo multiplicador sea bastante sencillo:

 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 = self.shouldBeArchived newConstraint.identifier = self.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 la 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() } 

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

Sin embargo, dado que sabe que desea cambiar el multiplicador, puede simplemente cambiar la constante multiplicándolo por sí mismo cuando se necesitan cambios, lo que a menudo es less código.

Una function auxiliar que uso para cambiar el multiplicador de una restricción de layout 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) 

Versión de Objective-C para Andrew Schreiber respuesta

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

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

En el file .m

 #import "NSLayoutConstraint+Multiplier.h" @implementation NSLayoutConstraint (Multiplier) -(instancetype)updateMultiplier:(CGFloat)multiplier { 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 deactivateConstraints:[NSArray arrayWithObjects:self, nil]]; [NSLayoutConstraint activateConstraints:[NSArray arrayWithObjects:newConstraint, nil]]; //NSLayoutConstraint.activateConstraints([newConstraint]) return newConstraint; } @end 

Más tarde, en ViewController, cree la salida para la restricción que desea actualizar.

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

y actualice el multiplicador donde quiera que desee a continuación …

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

Puede cambiar la propiedad "constante" para lograr el mismo objective con un poco de matemáticas. Suponga que su multiplicador pnetworkingeterminado en la restricción es 1.0f. Este es el código de Xamarin C # que se puede traducir fácilmente a objective-c

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

Uno puede leer:

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

en esta página de documentation . ¿Eso no significa que uno debería ser capaz de modificar el multiplicador (ya que es un var)?