178 votes

Puis-je changer la propriété de multiplicateur pour NSLayoutConstraint ?

J'ai créé deux vues dans une super vue, puis j'ai ajouté des contraintes entre les vues :

_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];

Maintenant, je veux changer la propriété du multiplicateur avec une animation, mais je n'arrive pas à comprendre comment changer la propriété du multiplicateur. (J'ai trouvé _coefficient dans la propriété privée dans le fichier d'en-tête NSLayoutConstraint.h, mais c'est privé.)

Comment puis-je changer la propriété du multiplicateur ?

Ma solution de contournement est de supprimer l'ancienne contrainte et d'ajouter la nouvelle avec une valeur différente pour multiplieur.

208voto

Voici une extension NSLayoutConstraint en Swift qui rend assez facile la définition d'un nouveau multiplicateur :

En Swift 3.0+

import UIKit
extension NSLayoutConstraint {
    /**
     Changer le multiplicateur de contrainte

     - 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
    }
}

Utilisation de la démo :

@IBOutlet weak var myDemoConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    let newMultiplier: CGFloat = 0.80
    myDemoConstraint = myDemoConstraint.setMultiplier(newMultiplier)

    //Si plus tard dans le cycle de vie de la vue, vous devrez peut-être appeler view.layoutIfNeeded() 
}

132voto

Jack Points 88446

Si vous avez seulement deux ensembles de multiplicateurs à appliquer, à partir de iOS8, vous pouvez ajouter les deux ensembles de contraintes et décider lesquels doivent être actifs à tout moment :

NSLayoutConstraint *standardConstraint, *zoomedConstraint;

// ...
// switch between constraints
standardConstraint.active = NO; // cette ligne doit toujours être la première ligne. parce que vous devez désactiver un avant d'activer l'autre. sinon ils seront en conflit.
zoomedConstraint.active = YES;
[self.view layoutIfNeeded]; // ou en utilisant [UIView animate ...]

Version Swift 5.0

var standardConstraint: NSLayoutConstraint!
var zoomedConstraint: NSLayoutConstraint!

// ...

// switch between constraints
standardConstraint.isActive = false // cette ligne doit toujours être la première ligne. parce que vous devez désactiver un avant d'activer l'autre. sinon ils seront en conflit.
zoomedConstraint.isActive = true
self.view.layoutIfNeeded() // ou en utilisant UIView.animate

60voto

Fruity Geek Points 4651

La propriété multiplier est en lecture seule. Vous devez supprimer l'ancienne NSLayoutConstraint et la remplacer par une nouvelle pour la modifier.

Cependant, puisque vous savez que vous voulez changer le multiplicateur, vous pouvez simplement modifier la constante en la multipliant vous-même lorsque des changements sont nécessaires, ce qui est souvent moins de code.

53voto

Evgeny Points 2765

Une fonction d'aide que j'utilise pour changer le multiplieur d'une contrainte de mise en page existante. Elle crée et active une nouvelle contrainte et désactive l'ancienne.

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
  }
}

Utilisation, changer le multiplieur en 1.2 :

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

46voto

Koti Tummala Points 736

Version Objective-C pour la réponse d'Andrew Schreiber

Créez la catégorie pour la classe NSLayoutConstraint et ajoutez la méthode dans le fichier .h comme ceci

    #import 

@interface NSLayoutConstraint (Multiplier)
-(instancetype)updateMultiplier:(CGFloat)multiplier;
@end

Dans le fichier .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

Plus tard dans le ViewController, créez la sortie pour la contrainte que vous souhaitez mettre à jour.

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

et mettez à jour le multiplicateur où vous le souhaitez comme ci-dessous..

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X