web-dev-qa-db-fra.com

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

J'ai créé deux vues dans une vue supérieure, 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é de multiplicateur avec animation, mais je ne peux pas comprendre comment changer la propriété de multiplicateur. (J'ai trouvé _coefficient dans une propriété privée dans le fichier d'en-tête NSLayoutConstraint.h, mais privé.)

Comment changer la propriété du multiplicateur? 

Ma solution consiste à supprimer l'ancienne contrainte et à ajouter la nouvelle avec une valeur différente pour multipler.

117
Bimawa

Si vous n'avez que deux ensembles de multiplicateurs à appliquer, à partir de iOS8 vous pouvez ajouter les deux ensembles de contraintes et choisir celles qui doivent être actives à tout moment:

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 ...]
100
Ja͢ck

Voici une extension NSLayoutConstraint dans Swift qui facilite le réglage d'un nouveau multiplicateur:

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

Dans Swift 3.0

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

Utilisation de la démo:

@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() 
}
133
Andrew Schreiber

La propriété multiplier est en lecture seule. Vous devez supprimer l'ancien NSLayoutConstraint et le remplacer par un nouveau pour le modifier. 

Cependant, puisque vous savez que vous souhaitez modifier le multiplicateur, vous pouvez simplement modifier la constante en la multipliant vous-même lorsque des modifications sont nécessaires, qui sont souvent moins codées. 

51
Fruity Geek

Une fonction d'assistance que j'utilise pour modifier multiplier d'une contrainte de présentation existante Il 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, changement de multiplicateur à 1.2:

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

Version Objective-C pour Andrew Schreiber answer

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

    #import <UIKit/UIKit.h>

@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 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];
36
Koti Tummala

Vous pouvez modifier la propriété "constante" à la place pour atteindre le même objectif avec un peu de calcul. Supposons que votre multiplicateur par défaut sur la contrainte est 1.0f. Ceci est le code Xamarin C # qui peut être facilement traduit en objective-c

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

Comme dans d'autres réponses expliquées: Vous devez supprimer la contrainte et en créer une nouvelle.


Vous pouvez éviter de renvoyer une nouvelle contrainte en créant une méthode statique pour NSLayoutConstraint avec le paramètre inout, ce qui vous permet de réaffecter la contrainte passée.

import UIKit

extension NSLayoutConstraint {

    static func setMultiplier(_ multiplier: CGFloat, of constraint: inout NSLayoutConstraint) {
        NSLayoutConstraint.deactivate([constraint])

        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
        newConstraint.shouldBeArchived = constraint.shouldBeArchived
        newConstraint.identifier = constraint.identifier

        NSLayoutConstraint.activate([newConstraint])
        constraint = newConstraint
    }

}

Exemple d'utilisation:

@IBOutlet weak var constraint: NSLayoutConstraint!

override func viewDidLoad() {
    NSLayoutConstraint.setMultiplier(0.8, of: &constraint)
    // view.layoutIfNeeded() 
}
1
Robert Dresler

Oui, w peut modifier les valeurs de multiplicateur, il suffit de créer une extension de NSLayoutConstraint et de l’utiliser comme suit ->

   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 = shouldBeArchived
        newConstraint.identifier = identifier

        NSLayoutConstraint.activate([newConstraint])
        return newConstraint
    }

            self.mainImageViewHeightMultiplier = self.mainImageViewHeightMultiplier.setMultiplier(375.0/812.0)
1
Rajan Singh

Basculer en modifiant la contrainte active dans le code comme suggéré par de nombreuses autres réponses ne fonctionnait pas pour moi. J'ai donc créé 2 contraintes, l'une installée et l'autre non, lier les deux au code, puis basculer en supprimant l'une et en ajoutant l'autre.

Par souci d’exhaustivité, pour lier la contrainte, faites glisser la contrainte vers le code à l’aide du bouton droit de la souris, comme pour tout autre élément graphique:

enter image description here

J'ai nommé une proportionIPad et l'autre proportionIPhone.

Ensuite, ajoutez le code suivant, à viewDidLoad

override open func viewDidLoad() {
   super.viewDidLoad()
   if ... {

       view.removeConstraint(proportionIphone)
       view.addConstraint(proportionIpad) 
   }     
}

J'utilise xCode 10 et Swift 5.0

1
ByteArtisan

AUCUN DU CODE CI-DESSUS TRAVAILLÉ POUR MOI SO APRÈS L'ESSAI DE MODIFIER MON PROPRE CODE CE CODE Ce code fonctionne dans Xcode 10 et Swift 4.2

import UIKit
extension NSLayoutConstraint {
/**
 Change multiplier constraint

 - parameter multiplier: CGFloat
 - returns: NSLayoutConstraintfor 
*/i
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
}
}



 @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() 
 }
0
Ullas Kumar

Voici une réponse basée sur la réponse de @ Tianfu en C #. D'autres réponses nécessitant l'activation et la désactivation de contraintes ne fonctionnaient pas pour moi.

    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()
}
0
RawMean

Pour modifier la valeur du multiplicateur, suivez les étapes ci-dessous: 1. Créez des points de vente pour la contrainte requise, par exemple someConstraint . 2. Modifiez la valeur du multiplicateur comme someConstraint.constant * = 0.8 ou une valeur de multiplicateur.

c'est ça, codage heureux.

0
Gulshan Kumar

supposons qu'un view1 dans le storyboard ait une contrainte de largeur par rapport à la vue principale (self.view en code) comme ceci

  view1Width = view * 0.7 + constant 

au lieu de créer 2 contraintes et de passer de l'une à l'autre en modifiant la propriété Active ORRR [en désactivant la contrainte actuelle avec l'ancien multiplicateur et en en créant une nouvelle avec un nouveau multiplicateur] laissez-la 1 contrainte et jouez avec elle 

supposons que je veuille changer le multiplicateur de view1 soit 0,9 au lieu de 0,7

Je peux faire ça

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

vous faites de même pour la soustraction 

0
Sh_Khan