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
.
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 ...]
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()
}
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.
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)
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];
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);
}
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()
}
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)
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:
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
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()
}
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()
}
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.
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