Loại bỏ tất cả các ràng buộc ảnh hưởng đến một UIView


87

Tôi có một UIView được đặt trên màn hình thông qua một số ràng buộc. Một số ràng buộc thuộc sở hữu của superview, một số ràng buộc khác thuộc sở hữu của tổ tiên khác (ví dụ: có lẽ thuộc tính view của UIViewController).

Tôi muốn loại bỏ tất cả các ràng buộc cũ này và đặt nó vào một nơi mới bằng cách sử dụng các ràng buộc mới.

Làm cách nào tôi có thể thực hiện việc này mà không cần tạo IBOutlet cho mọi ràng buộc đơn lẻ và phải nhớ chế độ xem nào sở hữu ràng buộc nói trên?

Nói một cách chi tiết, cách tiếp cận đơn giản sẽ là tạo một loạt các IBOutlet cho mỗi ràng buộc và sau đó sẽ liên quan đến việc gọi mã như:

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

Vấn đề với mã này là ngay cả trong trường hợp đơn giản nhất, tôi sẽ cần tạo 2 IBOutlet. Đối với các bố cục phức tạp, điều này có thể dễ dàng đạt được 4 hoặc 8 IBOutlet yêu cầu. Hơn nữa, tôi cần đảm bảo rằng lệnh gọi của tôi để loại bỏ ràng buộc đang được gọi trên dạng xem thích hợp. Ví dụ, hãy tưởng tượng rằng nó myViewsLeftConstraintđược sở hữu bởi viewA. Nếu tôi vô tình gọi [self.view removeConstraint:self.myViewsLeftConstraint]thì sẽ không có chuyện gì xảy ra.

Lưu ý: Các ràng buộc của phương thứcAffectingLayoutForAxis trông có vẻ hứa hẹn, nhưng chỉ dành cho mục đích gỡ lỗi.


Cập nhật: Nhiều người trong số các câu trả lời tôi nhận được thỏa thuận với self.constraints, self.superview.constraintshoặc một số biến thể của những người. Các giải pháp này sẽ không hoạt động vì các phương thức đó chỉ trả về các ràng buộc thuộc sở hữu của chế độ xem, không trả về các ràng buộc ảnh hưởng đến chế độ xem.

Để làm rõ vấn đề với các giải pháp này, hãy xem xét hệ thống phân cấp chế độ xem này:

  • Ông nội
    • Bố
      • Tôi
        • Con trai
        • Con gái
      • Anh trai
    • Chú

Bây giờ hãy tưởng tượng chúng ta tạo các ràng buộc sau và luôn gắn chúng với tổ tiên chung gần nhất của chúng:

  • C0: Tôi: cùng top với Son (thuộc sở hữu của Tôi)
  • C1: Tôi: chiều rộng = 100 (thuộc sở hữu của Tôi)
  • C2: Tôi: cùng chiều cao với Anh (thuộc sở hữu của Cha)
  • C3: Tôi: cùng top với Bác (thuộc sở hữu của Ông)
  • C4: Tôi: cùng bên trái với Ông (thuộc sở hữu của Ông)
  • C5: Anh trai: cùng bên trái với Cha (thuộc sở hữu của Cha)
  • C6: Chú: cùng bên trái với Ông (thuộc sở hữu của Ông)
  • C7: Con trai: cùng bên trái với Con gái (thuộc sở hữu của Tôi)

Bây giờ hãy tưởng tượng chúng ta muốn loại bỏ tất cả các ràng buộc ảnh hưởng Me. Bất kỳ giải pháp thích hợp nào nên loại bỏ [C0,C1,C2,C3,C4]và không có gì khác.

Nếu tôi sử dụng self.constraints(nơi tự là Tôi), tôi sẽ nhận được [C0,C1,C7], vì đó là những ràng buộc duy nhất thuộc sở hữu của Tôi. Rõ ràng là sẽ không đủ để loại bỏ điều này vì nó bị thiếu [C2,C3,C4]. Hơn nữa, nó đang loại bỏ C7không cần thiết.

Nếu tôi sử dụng self.superview.constraints(nơi tự là Tôi), tôi sẽ nhận được [C2,C5], vì đó là những ràng buộc thuộc sở hữu của Cha. Rõ ràng là chúng tôi không thể xóa tất cả những điều này vì C5hoàn toàn không liên quan đến Me.

Nếu tôi sử dụng grandfather.constraints, tôi sẽ nhận được [C3,C4,C6]. Một lần nữa, chúng tôi không thể xóa tất cả những thứ này vì nó C6sẽ vẫn còn nguyên vẹn.

Cách tiếp cận brute force là lặp lại từng tổ tiên của chế độ xem (bao gồm cả chính nó) và xem liệu chế độ xem có firstItemhay secondItemkhông; nếu vậy, hãy loại bỏ ràng buộc đó. Điều này sẽ dẫn đến một giải pháp chính xác, quay trở lại [C0,C1,C2,C3,C4]và chỉ những ràng buộc đó.

Tuy nhiên, tôi hy vọng có một giải pháp thanh lịch hơn là phải lặp lại toàn bộ danh sách tổ tiên.


Làm thế nào về việc bạn đặt một số nhận dạng cho tất cả các ràng buộc bạn muốn loại bỏ? Bằng cách này, bạn không cần phải giữ một lối thoát cho chúng.
nsuinteger

Câu trả lời:


69

Cách tiếp cận này đã làm việc cho tôi:

@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

Sau khi thực thi xong, khung nhìn của bạn vẫn ở nguyên vị trí cũ vì nó tạo ra các ràng buộc tự động khôi phục. Khi tôi không làm điều này, khung nhìn thường biến mất. Ngoài ra, nó không chỉ loại bỏ các ràng buộc khỏi superview mà còn vượt qua tất cả các cách lên vì có thể có các ràng buộc ảnh hưởng đến nó trong các khung nhìn tổ tiên.


Phiên bản Swift 4

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

3
Đây sẽ là câu trả lời chính thức.
Jason Crocker

tại sao bạn có self.translatesAutoresizingMaskIntoConstraints = YES; ? bạn thực sự không bao giờ muốn điều này cho các khung nhìn mà bạn đang thiết lập với các ràng buộc?
lensovet

4
Tôi đang loại bỏ những hạn chế, vì vậy tôi muốn sử dụng những hạn chế autoresize sau khi tôi loại bỏ các hạn chế khác để giữ nó tại chỗ, mà không có dòng trong mã của tôi quan điểm sẽ biến mất
marchinram

Tôi cần ghi lại tất cả các ràng buộc trên một dạng xem cho mục đích gỡ lỗi và tôi có thể sửa đổi câu trả lời này một chút để làm điều đó. +1
ớtNUT

Điều này sẽ loại bỏ không chính xác C7. Tuy nhiên, nó sẽ dễ dàng sửa chữa nếu bạn xóa [self removeConstraints:self.constraints];và thay đổi UIView *superview = self.superview;thành UIView *superview = self;.
Senseful

49

Giải pháp duy nhất mà tôi đã tìm thấy cho đến nay là xóa chế độ xem khỏi chế độ xem siêu cấp của nó:

[view removeFromSuperview]

Điều này có vẻ như nó loại bỏ tất cả các ràng buộc ảnh hưởng đến bố cục của nó và sẵn sàng được thêm vào superview và có các ràng buộc mới được đính kèm. Tuy nhiên, nó cũng sẽ xóa không chính xác bất kỳ lượt xem phụ nào khỏi hệ thống phân cấp và loại bỏ [C7]không chính xác.


Bạn có thể sử dụng các thuộc tính firstItem và secondItem của các ràng buộc để kiểm tra xem chúng có áp dụng cho chế độ xem của bạn không và lặp qua hệ thống phân cấp chế độ xem để tìm tất cả chúng. Tuy nhiên, tôi nghĩ rằng xóa và thêm lại là một giải pháp tốt hơn. Tôi muốn xem trường hợp sử dụng của bạn vì có vẻ như đây là một điều rất tồi tệ đang làm. Các ràng buộc của bạn có thể dễ dàng trở nên hoàn toàn không hợp lệ vì các khung nhìn khác có thể dựa vào các ràng buộc đó để bố trí đúng cách.
bjtitus

@bjtitus: Điểm tốt. Tuy nhiên, trong trường hợp cụ thể này, tôi đang định vị lại một chế độ xem không có gì phụ thuộc vào nó. Nó sử dụng các khung nhìn khác để biết vị trí cần đặt, và không có khung nhìn nào sử dụng nó để biết vị trí cần đặt.
Senseful

Không phải là giải pháp duy nhất, nhưng rất đơn giản. Trong trường hợp sử dụng của tôi, tôi vừa xóa chế độ xem khỏi superview và sau đó thêm lại sau.
Marián Černý

48

Bạn có thể loại bỏ tất cả các ràng buộc trong một dạng xem bằng cách thực hiện điều này:

self.removeConstraints(self.constraints)

CHỈNH SỬA: Để loại bỏ các ràng buộc của tất cả các chế độ xem phụ, hãy sử dụng tiện ích mở rộng sau trong Swift:

extension UIView {
    func clearConstraints() {
        for subview in self.subviews {
            subview.clearConstraints()
        }
        self.removeConstraints(self.constraints)
    }
}

22
Vấn đề với giải pháp này là nó chỉ loại bỏ các ràng buộc mà chế độ xem này sở hữu (ví dụ như chiều rộng và chiều cao của nó). Nó không loại bỏ những thứ như các ràng buộc hàng đầu và hàng đầu.
Senseful

2
Tôi chưa xác minh nhận xét của bạn ở trên. Tuy nhiên, tôi tin rằng điều này sẽ hoạt động giống như hoặc tốt hơn ở trên, [NSLayoutConstraint deactivateConstraints: self.constraints];
emdog4

2
Điều đó sẽ gặp phải vấn đề tương tự như giải pháp ban đầu. self.constraintschỉ trả về các ràng buộc selfsở hữu, không phải tất cả các ràng buộc có ảnh hưởng self.
Senseful

1
Tôi hiểu những gì bạn đang nói bây giờ. Trong câu trả lời của tôi , tôi đang xóa các ràng buộc khỏi ContentView của UITableViewCell. Phương thức updateConstraints sau đó sẽ thêm các ràng buộc cho tất cả các lần xem phụ và đặt lại bố cục. Trong nhận xét đầu tiên của tôi ở trên, tôi nên nhập self.view.constraints. Cả self.view và self.contentView đều ở trên cùng của hệ thống phân cấp chế độ xem. Đặt TranslatesAutoresizingMasksToConstraints = CÓ trên self.view hoặc self.contentView là một ý tưởng tồi. ;-). Tôi không thích các lệnh gọi tới addSubview: trong phương thức updateConstraints của tôi, việc xóa chế độ xem khỏi hệ thống phân cấp có vẻ không cần thiết đối với imo.
emdog 4

Tôi vừa cập nhật câu hỏi để cho biết lý do tại sao một giải pháp như thế này không hoạt động cho những gì tôi đang tìm kiếm. Giả sử bạn đang ở trong UITableViewCell thì contentView tương đương là Grandfather. Do đó, giải pháp của bạn sẽ loại bỏ [C6]không chính xác và không loại bỏ không chính xác [C0,C1,C2].
Senseful

20

Có hai cách để đạt được điều đó theo Tài liệu dành cho nhà phát triển của Apple

1. NSLayoutConstraint.deactivateConstraints

Đây là một phương pháp tiện lợi cung cấp một cách dễ dàng để hủy kích hoạt một tập hợp các ràng buộc bằng một lần gọi. Tác dụng của phương pháp này cũng giống như việc đặt thuộc tính isActive của mỗi ràng buộc thành false. Thông thường, sử dụng phương pháp này hiệu quả hơn việc hủy kích hoạt từng ràng buộc riêng lẻ.

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

// Usage
NSLayoutConstraint.deactivate(yourView.constraints)

2. UIView.removeConstraints(Không được chấp nhận cho> = iOS 8.0)

Khi phát triển cho iOS 8.0 trở lên, hãy sử dụng phương thức deactivateConstraints: của lớp NSLayoutConstraints: thay vì gọi trực tiếp phương thức removeConstraints:. Phương thức deactivateConstraints: tự động loại bỏ các ràng buộc khỏi các khung nhìn chính xác.

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

// Usage
yourView.removeConstraints(yourView.constraints)

Lời khuyên

Sử dụng Storyboardcác s hoặc XIBs có thể gây khó khăn trong việc định cấu hình các ràng buộc như đã đề cập trong kịch bản của bạn, bạn phải tạo IBOutlet cho từng cái bạn muốn loại bỏ. Mặc dù vậy, hầu hết thời gian đều Interface Buildertạo ra nhiều rắc rối hơn là giải quyết được.

Do đó, khi có nội dung rất động và các trạng thái khác nhau của chế độ xem, tôi sẽ đề xuất:

  1. Tạo chế độ xem của bạn theo chương trình
  2. Bố trí chúng và sử dụng NSLayoutAnchor
  3. Nối từng ràng buộc có thể bị xóa sau này vào một mảng
  4. Xóa chúng mọi lúc trước khi áp dụng trạng thái mới

Mã đơn giản

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

Người giới thiệu

  1. NSLayoutConstraint
  2. UIView

2
Hãy cẩn thận. Các chế độ xem chỉ định kích thước nội dung bên trong sẽ được iOS thêm tự động NSContentSizeLayoutConstraint. Loại bỏ điều này bằng cách truy cập thuộc tính yourView.constraints bình thường sẽ phá vỡ tự động thanh toán trên các chế độ xem đó.
TigerCoding

Vấn đề với giải pháp này là nó chỉ loại bỏ các ràng buộc mà chế độ xem này sở hữu (ví dụ như chiều rộng và chiều cao của nó). Nó không loại bỏ những thứ như các ràng buộc hàng đầu và hàng đầu.
Senseful

Vâng, những gì Senseful đã nói. Mặc dù những phương pháp này có tồn tại, nhưng chúng không tự giải quyết được vấn đề mà câu hỏi thực sự đang đặt ra.
GSnyder

18

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

Điều này sẽ bị lỗi nếu chế độ xem của bạn không có chế độ xem siêu tốc trong 'chế độ xem siêu tốc!'. Vui lòng gói phần thành 'if let superview = superview' :)
Bersaelor

1
Điều này sẽ không loại bỏ tất cả các ràng buộc. Hạn chế đưa phụ huynh gần nhất của 2 quan điểm bị ảnh hưởng, vì vậy nếu bạn thực hiện một hạn chế mà không chia sẻ SuperView quan điểm này, khó khăn đó sẽ không được gỡ bỏ ...
vrwim

2
có lẽ chính xác hơn sẽ được so sánh sắc if c.firstItem === selfthay vì đúc as? UIViewvà kiểm tra bình đẳng với==
user1244109

Có thể không nên sử dụng removeConstraints: from apple doc: // Phương thức removeConstraints sẽ không được dùng nữa trong bản phát hành trong tương lai và nên tránh. Thay vào đó, hãy sử dụng + [NSLayoutConstraint hủy kích hoạtConstraints:].
eonist

@eonist câu trả lời là 3 năm trước. Thay vì chỉ trích bạn nên chỉnh sửa nó.
Alexander Volkov

5

Chi tiết

  • Xcode 10.2.1 (10E1001), Swift 5

Giải pháp

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

Sử dụng

print("constraints: \(view.getAllConstraints().count), subviews: \(view.getAllSubviews().count)")
view.deactivateAllConstraints()

1
Nó khá đẹp.
eonist

2

Một giải pháp nhanh chóng:

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

Điều quan trọng là phải đi qua tất cả các bậc cha mẹ, vì những ràng buộc giữa hai yếu tố là do tổ tiên chung nắm giữ, vì vậy chỉ xóa siêu quan sát như chi tiết trong câu trả lời này là không đủ tốt và bạn có thể gặp phải bất ngờ tồi tệ sau này.


2

Dựa trên các câu trả lời trước (nhanh 4)

Bạn có thể sử dụng InstantConstraints khi không muốn thu thập dữ liệu toàn bộ cấu trúc phân cấp.

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

2

Tôi sử dụng phương pháp sau để loại bỏ tất cả các ràng buộc khỏi chế độ xem:

.h tệp:

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

tệp .m:

+ (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]];
    }
}

Bạn cũng có thể đọc bài đăng này trên blog của tôi để hiểu rõ hơn về cách nó hoạt động đằng sau mui xe.

Nếu bạn cần kiểm soát chi tiết hơn, tôi muốn mạnh mẽ khuyến cáo chuyển sang Masonry , một lớp khuôn khổ mạnh mẽ mà bạn có thể sử dụng bất cứ khi nào bạn cần phải xử lý đúng đắn các ràng buộc theo chương trình.


2
Còn anh chị em thì sao?
zrslv

2

Cách tiếp cận dễ dàng và hiệu quả hơn là xóa chế độ xem khỏi superView và thêm lại dưới dạng chế độ xem phụ. điều này khiến tất cả các ràng buộc về lượt xem phụ được xóa tự động.😉


1

Với mục tiêuC

[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];
}

0

Bạn có thể sử dụng một cái gì đó như thế này:

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

Về cơ bản, điều này là liệt kê tất cả các ràng buộc trên superview của viewA và loại bỏ tất cả các ràng buộc liên quan đến viewA.

Sau đó, phần thứ hai loại bỏ các ràng buộc khỏi viewA bằng cách sử dụng mảng các ràng buộc của viewA.


1
Vấn đề với giải pháp này là nó chỉ loại bỏ các ràng buộc thuộc sở hữu của superview. Nó không loại bỏ tất cả các ràng buộc ảnh hưởng đến chế độ xem. (Ví dụ: bạn có thể dễ dàng thiết lập các ràng buộc trên superview của superview, điều này sẽ không bị xóa bằng cách sử dụng giải pháp này.)
Senseful

Tôi vừa cập nhật câu hỏi để chỉ ra lý do tại sao giải pháp này sẽ không hoạt động. Đây là cách gần đúng nhất, vì nó gần với giải pháp bạo lực nhất mà tôi đã đề cập ở trên. Tuy nhiên, giải pháp này sẽ loại bỏ không chính xác [C7]và sẽ không loại bỏ không chính xác [C3,C4].
Senseful

bạn có thể thiết kế phương pháp để thu thập thông tin về hệ thống phân cấp. Nhưng giải pháp này là đủ tốt, vì dù sao thì bạn cũng nên thêm các ràng buộc phía trên superview ngay lập tức. IMO
eonist

0

(Tính đến ngày 31 tháng 7 năm 2017)

SWIFT 3

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

Mục tiêu C

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

Đây là cách dễ nhất để nhanh chóng loại bỏ tất cả các ràng buộc tồn tại trên một UIView. Chỉ cần chắc chắn thêm UIView trở lại với các ràng buộc mới hoặc khung mới sau đó =)


0

Sử dụng trình tự có thể tái sử dụng

Tôi quyết định tiếp cận điều này theo cách 'tái sử dụng' hơn. Vì việc tìm kiếm tất cả các ràng buộc ảnh hưởng đến một chế độ xem là cơ sở cho tất cả những điều trên, tôi quyết định triển khai một chuỗi tùy chỉnh trả về tất cả chúng cho tôi, cùng với các chế độ xem riêng.

Điều đầu tiên cần làm là xác định một phần mở rộng trên Arrayscác NSLayoutConstraintmà trả về tất cả các yếu tố ảnh hưởng đến một cái nhìn cụ thể.

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

Sau đó, chúng tôi sử dụng tiện ích mở rộng đó trong một chuỗi tùy chỉnh trả về tất cả các ràng buộc ảnh hưởng đến chế độ xem đó, cùng với các chế độ xem thực sự sở hữu chúng (có thể ở bất kỳ đâu trên hệ thống phân cấp chế độ xem)

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

Cuối cùng, chúng tôi khai báo một tiện ích mở rộng trên UIViewđể hiển thị tất cả các ràng buộc ảnh hưởng đến nó trong một thuộc tính đơn giản mà bạn có thể truy cập bằng một cú pháp đơn giản cho từng cái.

extension UIView {

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

Bây giờ chúng ta có thể lặp lại tất cả các ràng buộc ảnh hưởng đến chế độ xem và làm những gì chúng ta muốn với chúng ...

Liệt kê các số nhận dạng của họ ...

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

Hủy kích hoạt chúng ...

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

Hoặc xóa chúng hoàn toàn ...

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

Thưởng thức!


0

Nhanh

Sau phần mở rộng UIView sẽ loại bỏ tất cả các ràng buộc Edge của một dạng xem:

extension UIView {
    func removeAllConstraints() {
        if let _superview = self.superview {
            self.removeFromSuperview()
            _superview.addSubview(self)
        }
    }
}

-1

Đây là cách để vô hiệu hóa tất cả các ràng buộc từ một chế độ xem cụ thể

 NSLayoutConstraint.deactivate(myView.constraints)

Vấn đề với giải pháp này là nó chỉ loại bỏ các ràng buộc mà chế độ xem này sở hữu (ví dụ như chiều rộng và chiều cao của nó). Nó không loại bỏ những thứ như các ràng buộc hàng đầu và hàng đầu.
Senseful
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.