Entfernen Sie alle Einschränkungen, die sich auf eine UIView auswirken

87

Ich habe eine UIView, die über verschiedene Einschränkungen auf dem Bildschirm angezeigt wird. Einige der Einschränkungen gehören der Übersicht, andere anderen Vorfahren (z. B. die Ansichtseigenschaft eines UIViewControllers).

Ich möchte all diese alten Einschränkungen entfernen und sie mithilfe neuer Einschränkungen an einem neuen Ort platzieren.

Wie kann ich dies tun, ohne für jede einzelne Einschränkung ein IBOutlet zu erstellen und mich daran erinnern zu müssen, welcher Ansicht diese Einschränkung gehört?

Um dies zu erläutern, würde der naive Ansatz darin bestehen, eine Reihe von IBOutlets für jede der Einschränkungen zu erstellen und dann Code aufzurufen, wie z.

[viewA removeConstraint:self.myViewsLeftConstraint];
[viewB removeConstraint:self.myViewsTopConstraint];
[viewB removeConstraint:self.myViewsBottomConstraint];
[self.view removeConstraint:self.myViewsRightConstraint];

Das Problem mit diesem Code ist, dass ich selbst im einfachsten Fall 2 IBOutlets erstellen müsste. Bei komplexen Layouts können leicht 4 oder 8 erforderliche IBOutlets erreicht werden. Außerdem müsste ich sicherstellen, dass mein Aufruf zum Entfernen der Einschränkung in der richtigen Ansicht aufgerufen wird. Stellen Sie sich zum Beispiel vor, das myViewsLeftConstraintgehört viewA. Wenn ich versehentlich anrufen [self.view removeConstraint:self.myViewsLeftConstraint]würde, würde nichts passieren.

Hinweis: Die Methode ConstrainctionsAffectingLayoutForAxis sieht vielversprechend aus, ist jedoch nur für Debugging-Zwecke vorgesehen.


Update: Viele der Antworten , die ich viel erhalte mit self.constraints, self.superview.constraintsoder irgendeine Variante davon. Diese Lösungen funktionieren nicht, da diese Methoden nur die Einschränkungen zurückgeben, die der Ansicht gehören, nicht diejenigen , die sich auf die Ansicht auswirken .

Berücksichtigen Sie diese Ansichtshierarchie, um das Problem mit diesen Lösungen zu klären:

  • Großvater
    • Vater
      • Mich
        • Sohn
        • Tochter
      • Bruder
    • Onkel

Stellen Sie sich nun vor, wir erstellen die folgenden Einschränkungen und hängen sie immer an den nächsten gemeinsamen Vorfahren an:

  • C0: Me: das gleiche Top wie Son (im Besitz von Me)
  • C1: Me: width = 100 (im Besitz von Me)
  • C2: Ich: gleiche Größe wie Bruder (im Besitz von Vater)
  • C3: Ich: das gleiche Top wie Onkel (im Besitz des Großvaters)
  • C4: Ich: gleich links wie Großvater (im Besitz von Großvater)
  • C5: Bruder: links wie Vater (im Besitz von Vater)
  • C6: Onkel: links wie Großvater (im Besitz von Großvater)
  • C7: Sohn: links wie Tochter (im Besitz von mir)

Stellen Sie sich nun vor, wir möchten alle betroffenen Einschränkungen entfernen Me. Jede richtige Lösung sollte entfernt werden [C0,C1,C2,C3,C4]und sonst nichts.

Wenn ich benutze self.constraints(wo ich selbst bin), werde ich bekommen [C0,C1,C7], da dies die einzigen Einschränkungen sind, die mir gehören. Offensichtlich würde es nicht ausreichen, dies zu entfernen, da es fehlt [C2,C3,C4]. Darüber hinaus wird es C7unnötig entfernt.

Wenn ich benutze self.superview.constraints(wo ich selbst bin), werde ich es bekommen [C2,C5], da dies die Zwänge sind, die Vater gehört. Offensichtlich können wir nicht alle diese entfernen, da dies C5völlig unabhängig ist Me.

Wenn ich benutze grandfather.constraints, werde ich bekommen [C3,C4,C6]. Auch hier können wir nicht alle entfernen, da dies C6intakt bleiben sollte.

Der Brute-Force-Ansatz besteht darin, alle Vorfahren der Ansicht (einschließlich sich selbst) zu durchlaufen und zu prüfen, ob firstItemoder ob secondItemdie Ansicht selbst vorhanden ist. Wenn ja, entfernen Sie diese Einschränkung. Dies führt zu einer korrekten Lösung, der Rückgabe [C0,C1,C2,C3,C4]und nur diesen Einschränkungen.

Ich hoffe jedoch, dass es eine elegantere Lösung gibt, als die gesamte Liste der Vorfahren durchlaufen zu müssen.

Sinnvoll
quelle
Wie wäre es, wenn Sie allen Einschränkungen, die Sie entfernen möchten, einen Bezeichner hinzufügen? Auf diese Weise müssen Sie keine Steckdose für sie halten.
nsuinteger

Antworten:

69

Dieser Ansatz hat bei mir funktioniert:

@interface UIView (RemoveConstraints)

- (void)removeAllConstraints;

@end


@implementation UIView (RemoveConstraints)

- (void)removeAllConstraints
{
    UIView *superview = self.superview;
    while (superview != nil) {
        for (NSLayoutConstraint *c in superview.constraints) {
            if (c.firstItem == self || c.secondItem == self) {
                [superview removeConstraint:c];
            }
        }
        superview = superview.superview;
    }

    [self removeConstraints:self.constraints];
    self.translatesAutoresizingMaskIntoConstraints = YES;
}

@end

Nach Abschluss der Ausführung bleibt Ihre Ansicht dort, wo sie war, da sie Einschränkungen für die automatische Größenänderung erstellt. Wenn ich das nicht mache, verschwindet die Ansicht normalerweise. Darüber hinaus werden nicht nur Einschränkungen aus der Übersicht entfernt, sondern ganz nach oben verschoben, da in den Ansichten der Vorfahren möglicherweise Einschränkungen auftreten.


Swift 4 Version

extension UIView {
    
    public func removeAllConstraints() {
        var _superview = self.superview
        
        while let superview = _superview {
            for constraint in superview.constraints {
                
                if let first = constraint.firstItem as? UIView, first == self {
                    superview.removeConstraint(constraint)
                }
                
                if let second = constraint.secondItem as? UIView, second == self {
                    superview.removeConstraint(constraint)
                }
            }
            
            _superview = superview.superview
        }
        
        self.removeConstraints(self.constraints)
        self.translatesAutoresizingMaskIntoConstraints = true
    }
}
Marchinram
quelle
3
Dies sollte die offizielle Antwort sein.
Jason Crocker
Warum haben Sie self.translatesAutoresizingMaskIntoConstraints = YES; ? Sie möchten dies buchstäblich nie für Ansichten, die Sie mit Einschränkungen einrichten?
Lensovet
4
Ich entferne die Einschränkungen, daher möchte ich die Einschränkungen für die automatische Größenänderung verwenden, nachdem ich die anderen Einschränkungen entfernt habe, um sie an Ort und Stelle zu halten. Ohne diese Zeile in meinem Code würde die Ansicht verschwinden
Marchinram
Ich musste alle Einschränkungen in einer Ansicht zu Debugging-Zwecken protokollieren und konnte diese Antwort dazu leicht ändern. +1
chiliNUT
Dies würde fälschlicherweise entfernen C7. Allerdings sollte es leicht sein , zu beheben , wenn Sie entfernen [self removeConstraints:self.constraints];und ändern UIView *superview = self.superview;zu UIView *superview = self;.
Sinnvoll
49

Die einzige Lösung, die ich bisher gefunden habe, besteht darin, die Ansicht aus der Übersicht zu entfernen:

[view removeFromSuperview]

Dies sieht so aus, als würde es alle Einschränkungen entfernen, die sich auf das Layout auswirken, und kann einer Übersicht hinzugefügt und mit neuen Einschränkungen versehen werden. Es werden jedoch auch Unteransichten fälschlicherweise aus der Hierarchie entfernt und [C7]falsch entfernt.

Sinnvoll
quelle
Sie können die Eigenschaften firstItem und secondItem der Einschränkungen verwenden, um zu überprüfen, ob sie für Ihre Ansicht gelten, und die Ansichtshierarchie durchlaufen, um alle zu finden. Ich denke jedoch, dass das Entfernen und erneute Hinzufügen eine bessere Lösung ist. Es würde mich interessieren, Ihren Anwendungsfall zu sehen, da dies anscheinend eine sehr schlechte Sache ist. Ihre Einschränkungen können leicht vollständig ungültig werden, da andere Ansichten möglicherweise auf diese Einschränkungen angewiesen sind, um sie ordnungsgemäß zu gestalten.
Bjtitus
@bjtitus: Guter Punkt. In diesem speziellen Fall positioniere ich jedoch eine Ansicht neu, von der nichts abhängig ist. Es werden andere Ansichten verwendet, um zu wissen, wo platziert werden soll, und es gibt keine Ansichten, die es verwenden, um zu wissen, wo platziert werden soll.
Sinnvoll
Nicht die einzige Lösung, aber sehr einfach. In meinem Anwendungsfall habe ich die Ansicht gerade aus der Übersicht entfernt und später wieder hinzugefügt.
Marián Černý
48

Sie können alle Einschränkungen in einer Ansicht folgendermaßen entfernen:

self.removeConstraints(self.constraints)

BEARBEITEN: Um die Einschränkungen aller Unteransichten zu entfernen, verwenden Sie die folgende Erweiterung in Swift:

extension UIView {
    func clearConstraints() {
        for subview in self.subviews {
            subview.clearConstraints()
        }
        self.removeConstraints(self.constraints)
    }
}
emdog4
quelle
22
Das Problem bei dieser Lösung besteht darin, dass nur die Einschränkungen entfernt werden, die dieser Ansicht gehören (z. B. ihre Breite und Höhe). Dinge wie die führenden und obersten Einschränkungen werden nicht entfernt.
Sinnvoller
2
Ich habe Ihren Kommentar oben nicht überprüft. Ich glaube jedoch, dass dies genauso oder besser als oben funktionieren würde. [NSLayoutConstraint disableConstraints: self.constraints];
Emdog4
2
Das hätte das gleiche Problem wie die ursprüngliche Lösung. self.constraintsGibt nur die eigenen Einschränkungen zurück self, nicht alle betroffenen Einschränkungen self.
Sinnvoller
1
Ich verstehe, was Sie jetzt sagen. In meiner Antwort entferne ich die Einschränkungen aus der contentView von UITableViewCell. Die Methode updateConstraints würde dann Einschränkungen für alle Unteransichten hinzufügen und das Layout zurücksetzen. In meinem ersten Kommentar oben hätte ich self.view.constraints eingeben sollen. Sowohl self.view als auch self.contentView befinden sich oben in der Ansichtshierarchie. Das Festlegen von translatesAutoresizingMasksToConstraints = YES in self.view oder self.contentView ist eine schlechte Idee. ;-). Ich mag keine Aufrufe von addSubview: In meiner updateConstraints-Methode erscheint es unnötig, die Ansicht aus der Hierarchie zu entfernen.
Emdog4
Ich habe gerade die Frage aktualisiert, um zu zeigen, warum eine solche Lösung für das, was ich tun möchte, nicht funktioniert. Angenommen, Sie befinden sich in einer UITableViewCell. Das Äquivalent zu contentView ist Großvater. Daher würde Ihre Lösung fälschlicherweise entfernt [C6]und fälschlicherweise nicht entfernt [C0,C1,C2].
Sinnvoll
20

Laut Apple Developer Documentation gibt es zwei Möglichkeiten, wie dies erreicht werden kann

1. NSLayoutConstraint.deactivateConstraints

Dies ist eine bequeme Methode, mit der Sie eine Reihe von Einschränkungen auf einfache Weise mit einem Aufruf deaktivieren können. Der Effekt dieser Methode ist der gleiche wie das Setzen der isActive-Eigenschaft jeder Einschränkung auf false. In der Regel ist die Verwendung dieser Methode effizienter, als jede Einschränkung einzeln zu deaktivieren.

// Declaration
class func deactivate(_ constraints: [NSLayoutConstraint])

// Usage
NSLayoutConstraint.deactivate(yourView.constraints)

2. UIView.removeConstraints(Veraltet für> = iOS 8.0)

Verwenden Sie bei der Entwicklung für iOS 8.0 oder höher die Methode deactivateConstraints: der NSLayoutConstraint-Klasse, anstatt die Methode removeConstraints: direkt aufzurufen. Die Methode disableConstraints: entfernt die Einschränkungen automatisch aus den richtigen Ansichten.

// Declaration
func removeConstraints(_ constraints: [NSLayoutConstraint])`

// Usage
yourView.removeConstraints(yourView.constraints)

Tipps

Die Verwendung von Storyboards oder XIBs kann bei der Konfiguration der in Ihrem Szenario genannten Einschränkungen so schwierig sein. Sie müssen IBOutlets für alle Einschränkungen erstellen, die Sie entfernen möchten. Trotzdem verursacht die meiste Zeit Interface Buildermehr Probleme als es löst.

Daher würde ich bei sehr dynamischen Inhalten und unterschiedlichen Ansichtszuständen Folgendes vorschlagen:

  1. Erstellen Sie Ihre Ansichten programmgesteuert
  2. Layouten Sie sie und verwenden Sie NSLayoutAnchor
  3. Hängen Sie jede Einschränkung, die später entfernt werden könnte, an ein Array an
  4. Löschen Sie sie jedes Mal, bevor Sie den neuen Status anwenden

Einfacher Code

private var customConstraints = [NSLayoutConstraint]()

private func activate(constraints: [NSLayoutConstraint]) {
    customConstraints.append(contentsOf: constraints)
    customConstraints.forEach { $0.isActive = true }
}

private func clearConstraints() {
    customConstraints.forEach { $0.isActive = false }
    customConstraints.removeAll()
}

private func updateViewState() {
    clearConstraints()

    let constraints = [
        view.leadingAnchor.constraint(equalTo: parentView.leadingAnchor),
        view.trailingAnchor.constraint(equalTo: parentView.trailingAnchor),
        view.topAnchor.constraint(equalTo: parentView.topAnchor),
        view.bottomAnchor.constraint(equalTo: parentView.bottomAnchor)
    ]

    activate(constraints: constraints)

    view.layoutIfNeeded()
}

Verweise

  1. NSLayoutConstraint
  2. UIView
E-Riddie
quelle
2
Achtung. Bei Ansichten, die eine intrinsische Inhaltsgröße angeben, wird NSContentSizeLayoutConstraint von iOS automatisch hinzugefügt. Wenn Sie dies entfernen, indem Sie auf die normale Eigenschaft yourView.constraints zugreifen, wird das automatische Layout für diese Ansichten unterbrochen.
TigerCoding
Das Problem bei dieser Lösung besteht darin, dass nur die Einschränkungen entfernt werden, die dieser Ansicht gehören (z. B. ihre Breite und Höhe). Dinge wie die führenden und obersten Einschränkungen werden nicht entfernt.
Sinnvoller
Ja, was Senseful gesagt hat. Obwohl diese Methoden existieren, lösen sie das Problem, nach dem die Frage tatsächlich gestellt wird, nicht alleine.
GSnyder
18

In Swift:

import UIKit

extension UIView {

    /**
     Removes all constrains for this view
     */
    func removeConstraints() {

        let constraints = self.superview?.constraints.filter{
            $0.firstItem as? UIView == self || $0.secondItem as? UIView == self
        } ?? []

        self.superview?.removeConstraints(constraints)
        self.removeConstraints(self.constraints)
    }
}
Alexander Volkov
quelle
Dies stürzt ab, wenn Ihre Ansicht keine Übersicht in "Übersicht!" Hat. Bitte wickeln Sie das Teil in ein 'if let Superview = Superview' :)
Bersaelor
1
Dadurch werden nicht alle Einschränkungen entfernt. Einschränkungen nehmen das nächste übergeordnete Element der beiden betroffenen Ansichten an. Wenn Sie also eine Einschränkung festlegen, die die Übersicht dieser Ansicht nicht teilt, wird diese Einschränkung nicht entfernt ...
vrwim
2
Vielleicht wäre es richtiger, die Identität zu vergleichen, if c.firstItem === selfanstatt sie zu as? UIView==
gießen
Sollte removeConstraints: from apple doc: // wahrscheinlich nicht verwenden. Die removeConstraints-Methode wird in einer zukünftigen Version nicht mehr unterstützt und sollte vermieden werden. Verwenden Sie stattdessen + [NSLayoutConstraint disableConstraints:].
Eonist
@eonist die Antwort ist vor 3 Jahren. Anstelle von Kritik sollten Sie es bearbeiten.
Alexander Volkov
5

Einzelheiten

  • Xcode 10.2.1 (10E1001), Swift 5

Lösung

import UIKit

extension UIView {

    func removeConstraints() { removeConstraints(constraints) }
    func deactivateAllConstraints() { NSLayoutConstraint.deactivate(getAllConstraints()) }
    func getAllSubviews() -> [UIView] { return UIView.getAllSubviews(view: self) }

    func getAllConstraints() -> [NSLayoutConstraint] {
        var subviewsConstraints = getAllSubviews().flatMap { $0.constraints }
        if let superview = self.superview {
            subviewsConstraints += superview.constraints.compactMap { (constraint) -> NSLayoutConstraint? in
                if let view = constraint.firstItem as? UIView, view == self { return constraint }
                return nil
            }
        }
        return subviewsConstraints + constraints
    }

    class func getAllSubviews(view: UIView) -> [UIView] {
        return view.subviews.flatMap { [$0] + getAllSubviews(view: $0) }
    }
}

Verwendung

print("constraints: \(view.getAllConstraints().count), subviews: \(view.getAllSubviews().count)")
view.deactivateAllConstraints()
Wassili Bodnarchuk
quelle
1
Es ist ziemlich schön.
Eonist
2

Eine schnelle Lösung:

extension UIView {
  func removeAllConstraints() {
    var view: UIView? = self
    while let currentView = view {
      currentView.removeConstraints(currentView.constraints.filter {
        return $0.firstItem as? UIView == self || $0.secondItem as? UIView == self
      })
      view = view?.superview
    }
  }
}

Es ist wichtig, alle Eltern durchzugehen, da die Einschränkungen zwischen zwei Elementen von den gemeinsamen Vorfahren eingehalten werden. Daher ist es nicht gut genug, nur die in dieser Antwort beschriebene Übersicht zu löschen , und Sie könnten später eine schlechte Überraschung erleben .

Guig
quelle
2

Basierend auf früheren Antworten (schnell 4)

Sie können sofortige Einschränkungen verwenden, wenn Sie nicht ganze Hierarchien crawlen möchten.

extension UIView {
/**
 * Deactivates immediate constraints that target this view (self + superview)
 */
func deactivateImmediateConstraints(){
    NSLayoutConstraint.deactivate(self.immediateConstraints)
}
/**
 * Deactivates all constrains that target this view
 */
func deactiveAllConstraints(){
    NSLayoutConstraint.deactivate(self.allConstraints)
}
/**
 * Gets self.constraints + superview?.constraints for this particular view
 */
var immediateConstraints:[NSLayoutConstraint]{
    let constraints = self.superview?.constraints.filter{
        $0.firstItem as? UIView === self || $0.secondItem as? UIView === self
        } ?? []
    return self.constraints + constraints
}
/**
 * Crawls up superview hierarchy and gets all constraints that affect this view
 */
var allConstraints:[NSLayoutConstraint] {
    var view: UIView? = self
    var constraints:[NSLayoutConstraint] = []
    while let currentView = view {
        constraints += currentView.constraints.filter {
            return $0.firstItem as? UIView === self || $0.secondItem as? UIView === self
        }
        view = view?.superview
    }
    return constraints
}
}
Eonist
quelle
2

Ich verwende die folgende Methode, um alle Einschränkungen aus einer Ansicht zu entfernen:

.h Datei:

+ (void)RemoveContraintsFromView:(UIView*)view 
    removeParentConstraints:(bool)parent 
    removeChildConstraints:(bool)child;

.m Datei:

+ (void)RemoveContraintsFromView:(UIView *)view 
    removeParentConstraints:(bool)parent 
    removeChildConstraints:(bool)child
{
    if (parent) {
        // Remove constraints between view and its parent.
        UIView *superview = view.superview;
        [view removeFromSuperview];
        [superview addSubview:view];
    }

    if (child) {
        // Remove constraints between view and its children.
        [view removeConstraints:[view constraints]];
    }
}

Sie können diesen Beitrag auch in meinem Blog lesen, um besser zu verstehen, wie er hinter der Haube funktioniert.

Wenn Sie eine genauere Steuerung benötigen, empfehle ich dringend, zu Masonry zu wechseln , einer leistungsstarken Framework-Klasse, die Sie verwenden können, wenn Sie Einschränkungen programmgesteuert richtig handhaben müssen.

Darkseal
quelle
2
Was ist mit Geschwistern?
zrslv
2

Der einfachere und effizientere Ansatz besteht darin, die Ansicht aus superView zu entfernen und erneut als Unteransicht hinzuzufügen. Dadurch werden alle Einschränkungen der Unteransicht automatisch entfernt

Hashem Aboonajmi
quelle
1

Mit objectivC

[self.superview.constraints enumerateObjectsUsingBlock:^(__kindof NSLayoutConstraint * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLayoutConstraint *constraint = (NSLayoutConstraint *)obj;
        if (constraint.firstItem == self || constraint.secondItem == self) {
            [self.superview removeConstraint:constraint];
        }
    }];
    [self removeConstraints:self.constraints];
}
Giang
quelle
0

Sie könnten so etwas verwenden:

[viewA.superview.constraints enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    NSLayoutConstraint *constraint = (NSLayoutConstraint *)obj;
    if (constraint.firstItem == viewA || constraint.secondItem == viewA) {
        [viewA.superview removeConstraint:constraint];
    }
}];

[viewA removeConstraints:viewA.constraints];

Grundsätzlich werden alle Einschränkungen in der Übersicht von viewA aufgelistet und alle Einschränkungen entfernt, die sich auf viewA beziehen.

Anschließend entfernt der zweite Teil die Einschränkungen aus viewA mithilfe des Arrays der Einschränkungen von viewA.

Tristan
quelle
1
Das Problem bei dieser Lösung besteht darin, dass nur die Einschränkungen entfernt werden, die der Übersicht gehören. Es werden nicht alle Einschränkungen entfernt, die sich auf die Ansicht auswirken. (ZB könnten Sie genauso einfach Einschränkungen für die Superview der Superview festlegen, die mit dieser Lösung nicht entfernt werden
könnten
Ich habe gerade die Frage aktualisiert, um zu zeigen, warum diese Lösung nicht funktioniert. Dies kommt der Richtigkeit am nächsten, da es der oben erwähnten Brute-Force-Lösung am nächsten kommt. Diese Lösung wird jedoch fälschlicherweise entfernt [C7]und fälschlicherweise nicht entfernt [C3,C4].
Sinnvoll
Sie können die Methode zum Crawlen der Hierarchie entwerfen. Diese Lösung ist jedoch gut genug, da Sie ohnehin Einschränkungen über der unmittelbaren Übersicht hinzufügen sollten. IMO
Eonist
0

(Stand 31. Juli 2017)

SWIFT 3

self.yourCustomView.removeFromSuperview()
self.yourCustomViewParentView.addSubview(self.yourCustomView)

Ziel c

[self.yourCustomView removeFromSuperview];
[self.yourCustomViewParentView addSubview:self.yourCustomView];

Dies ist der einfachste Weg, um alle in einer UIView vorhandenen Einschränkungen schnell zu entfernen. Stellen Sie einfach sicher, dass Sie das UIView mit seinen neuen Einschränkungen oder dem neuen Frame danach wieder hinzufügen =)

BennyTheNerd
quelle
0

Verwenden einer wiederverwendbaren Sequenz

Ich beschloss, dies auf eine "wiederverwendbarere" Weise anzugehen. Da das Auffinden aller Einschränkungen, die sich auf eine Ansicht auswirken, die Grundlage für alle oben genannten Punkte ist, habe ich beschlossen, eine benutzerdefinierte Sequenz zu implementieren, die sie alle zusammen mit den eigenen Ansichten für mich zurückgibt.

Das erste , was zu tun ist , eine Erweiterung definieren auf Arraysder NSLayoutConstraintalle Elemente , die Erträge eine bestimmte Ansicht zu beeinflussen.

public extension Array where Element == NSLayoutConstraint {

    func affectingView(_ targetView:UIView) -> [NSLayoutConstraint] {

        return self.filter{

            if let firstView = $0.firstItem as? UIView,
                firstView == targetView {
                return true
            }

            if let secondView = $0.secondItem as? UIView,
                secondView == targetView {
                return true
            }

            return false
        }
    }
}

Wir verwenden diese Erweiterung dann in einer benutzerdefinierten Sequenz, die alle Einschränkungen zurückgibt, die diese Ansicht betreffen, sowie die Ansichten, deren Eigentümer sie tatsächlich sind (die sich an einer beliebigen Stelle in der Ansichtshierarchie befinden können).

public struct AllConstraintsSequence : Sequence {

    public init(view:UIView){
        self.view = view
    }

    public let view:UIView

    public func makeIterator() -> Iterator {
        return Iterator(view:view)
    }

    public struct Iterator : IteratorProtocol {

        public typealias Element = (constraint:NSLayoutConstraint, owningView:UIView)

        init(view:UIView){
            targetView  = view
            currentView = view
            currentViewConstraintsAffectingTargetView = currentView.constraints.affectingView(targetView)
        }

        private let targetView  : UIView
        private var currentView : UIView
        private var currentViewConstraintsAffectingTargetView:[NSLayoutConstraint] = []
        private var nextConstraintIndex = 0

        mutating public func next() -> Element? {

            while(true){

                if nextConstraintIndex < currentViewConstraintsAffectingTargetView.count {
                    defer{nextConstraintIndex += 1}
                    return (currentViewConstraintsAffectingTargetView[nextConstraintIndex], currentView)
                }

                nextConstraintIndex = 0

                guard let superview = currentView.superview else { return nil }

                self.currentView = superview
                self.currentViewConstraintsAffectingTargetView = currentView.constraints.affectingView(targetView)
            }
        }
    }
}

Schließlich deklarieren wir eine Erweiterung für UIView, um alle sie betreffenden Einschränkungen in einer einfachen Eigenschaft verfügbar zu machen, auf die Sie mit einer einfachen Syntax für jede zugreifen können.

extension UIView {

    var constraintsAffectingView:AllConstraintsSequence {
        return AllConstraintsSequence(view:self)
    }
}

Jetzt können wir alle Einschränkungen, die sich auf eine Ansicht auswirken, iterieren und mit ihnen tun, was wir wollen ...

Listen Sie ihre Kennungen auf ...

for (constraint, _) in someView.constraintsAffectingView{
    print(constraint.identifier ?? "No identifier")
}

Deaktiviere sie ...

for (constraint, _) in someView.constraintsAffectingView{
    constraint.isActive = false
}

Oder entfernen Sie sie vollständig ...

for (constraint, owningView) in someView.constraintsAffectingView{
    owningView.removeConstraints([constraint])
}

Genießen!

Mark A. Donohoe
quelle
0

Schnell

Die folgende UIView-Erweiterung entfernt alle Kanteneinschränkungen einer Ansicht:

extension UIView {
    func removeAllConstraints() {
        if let _superview = self.superview {
            self.removeFromSuperview()
            _superview.addSubview(self)
        }
    }
}
Gurjit Singh
quelle
-1

Auf diese Weise können Sie alle Einschränkungen in einer bestimmten Ansicht deaktivieren

 NSLayoutConstraint.deactivate(myView.constraints)
user2501116
quelle
Das Problem bei dieser Lösung besteht darin, dass nur die Einschränkungen entfernt werden, die dieser Ansicht gehören (z. B. ihre Breite und Höhe). Dinge wie die führenden und obersten Einschränkungen werden nicht entfernt.
Sinnvoller