it-swarm.com.de

Kann ich die Multiplikator-Eigenschaft für NSLayoutConstraint ändern?

Ich habe zwei Ansichten in einem Superview erstellt und dann Einschränkungen zwischen den Ansichten hinzugefügt:

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

Jetzt möchte ich die Multiplikator-Eigenschaft mit Animation ändern, aber ich kann nicht herausfinden, wie die Multiplikator-Eigenschaft geändert werden kann. (Ich habe _coefficient in der privaten Eigenschaft in der Header-Datei NSLayoutConstraint.h gefunden, aber privat.)

Wie ändere ich die Multiplikator-Eigenschaft? 

Mein Workaround besteht darin, die alte Einschränkung zu entfernen und die neue mit einem anderen Wert für multipler hinzuzufügen.

117
Bimawa

Wenn Sie nur zwei Sätze von Multiplikatoren haben, die angewendet werden müssen, können Sie ab iOS8 / beide Sätze von Abhängigkeiten hinzufügen und entscheiden, welche jederzeit aktiv sein sollen:

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

Hier ist eine NSLayoutConstraint-Erweiterung in Swift, die das Einstellen eines neuen Multiplikators ziemlich einfach macht:

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

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

Demo-Nutzung:

@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

Die multiplier-Eigenschaft ist schreibgeschützt. Sie müssen den alten NSLayoutConstraint entfernen und durch einen neuen ersetzen, um ihn zu ändern. 

Da Sie jedoch wissen, dass Sie den Multiplikator ändern möchten, können Sie die Konstante einfach ändern, indem Sie sie selbst multiplizieren, wenn Änderungen erforderlich sind. Dies ist häufig weniger Code. 

51
Fruity Geek

Eine Hilfsfunktion, die ich verwende, um den multiplier einer vorhandenen Layoutbedingung zu ändern. Es erstellt und aktiviert eine neue Einschränkung und deaktiviert die alte. 

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

Verbrauch, Multiplikator auf 1,2 ändern:

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

Objective-C-Version für die Antwort von Andrew Schreiber

Erstellen Sie die Kategorie für NSLayoutConstraint-Klasse, und fügen Sie die Methode in der .h-Datei wie folgt hinzu

    #import <UIKit/UIKit.h>

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

In der .m-Datei

#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

Erstellen Sie später im ViewController den Ausgang für die Einschränkung, die Sie aktualisieren möchten.

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

und aktualisieren Sie den Multiplikator wo immer Sie möchten ..

self.topConstraint = [self.topConstraint updateMultiplier:0.9099];
36
Koti Tummala

Sie können stattdessen die "konstante" Eigenschaft ändern, um mit ein wenig Rechenaufwand dasselbe Ziel zu erreichen. Angenommen, Ihr Standardmultiplikator für die Einschränkung ist 1,0f. Dies ist Xamarin C # -Code, der leicht in Objective-C übersetzt werden kann

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

Wie in anderen Antworten erläutert: Sie müssen die Einschränkung entfernen und eine neue erstellen.


Sie können die Rückgabe einer neuen Einschränkung vermeiden, indem Sie eine statische Methode für NSLayoutConstraint mit dem Parameter inout erstellen, mit der Sie die übergebene Einschränkung neu zuweisen können

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
    }

}

Beispielverwendung:

@IBOutlet weak var constraint: NSLayoutConstraint!

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

Ja, Sie können die Multiplikatorwerte ändern, indem Sie einfach eine Erweiterung von NSLayoutConstraint erstellen und wie -> verwenden

   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

Wechseln durch Ändern der aktiven Einschränkung im Code, wie in vielen anderen Antworten vorgeschlagen, hat bei mir nicht funktioniert. Also habe ich 2 Einschränkungen erstellt, eine installiert und die andere nicht. Binde beide an den Code und wechsle dann, indem du eine entfernst und die andere hinzufügst.

Um der Vollständigkeit halber die Einschränkung zu binden, ziehen Sie die Einschränkung wie jedes andere grafische Element mit der rechten Maustaste auf den Code:

enter image description here

Ich habe ein proportionIPad und das andere proportionIPhone genannt.

Fügen Sie dann bei viewDidLoad den folgenden Code hinzu

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

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

Ich verwende xCode 10 und Swift 5.0

1
ByteArtisan

KEINER DER OBEN GENANNTEN CODES HAT FÜR MICH GEARBEITET SO NACH DEM VERSUCH, MEINEN EIGENEN CODE ZU ÄNDERN DIESEN CODE Dieser Code funktioniert in Xcode 10 und 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

Hier ist eine Antwort basierend auf @ Tianfus Antwort in C #. Andere Antworten, die eine Aktivierung und Deaktivierung von Einschränkungen erfordern, haben für mich nicht funktioniert.

    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

Führen Sie die folgenden Schritte aus, um den Wert des Multiplikators zu ändern: 1. Erstellen Sie Auslässe für die erforderliche Einschränkung, z. B. someConstraint . 2. Ändern Sie den Multiplikatorwert wie someConstraint.constant * = 0,8 oder einen beliebigen Multiplikatorwert.

das ist es, glückliche Kodierung.

0
Gulshan Kumar

angenommen, ein view1 im Storyboard hat eine Breitenbeschränkung für die Hauptansicht (self.view in code) wie folgt

  view1Width = view * 0.7 + constant 

anstatt zwei Bedingungen zu erstellen und zwischen ihnen zu wechseln, indem Sie die Active-Eigenschaft ORRR ändern [indem Sie die aktuelle Einschränkung mit dem alten Multiplikator deaktivieren und eine neue mit einem neuen Multiplikator erstellen], belassen Sie es 1 Einschränkung und spielen mit seiner Konstanten 

angenommen, ich möchte den view1-Multiplikator auf 0,9 anstelle von 0,7 ändern

Ich kann das tun

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

das Gleiche tun Sie für die Subtraktion 

0
Sh_Khan