簡體   English   中英

在設備輪換時保持autolayout約束活動狀態

[英]Keep autolayout constraints active status on device rotation

我注意到,當我以編程方式更新自動布局約束時,在旋轉屏幕時會恢復所有更改。

重現問題:

  • 帶有UIView的基本Storyboard界面和2個約束:

    1. width等於superview.width(乘數1)有效
    2. 寬度等於superview.width(乘數1/2)禁用
  • 使用IBOutlet創建並鏈接這兩個約束

  • 以編程方式禁用第一個約束並啟用第二個約束。
  • 旋轉設備,第一個約束處於活動狀態,第二個約束處於禁用狀態。

對我來說似乎是一個錯誤。

你怎么看 ?

截圖:

故事板: 在此輸入圖像描述

約束#1:

在此輸入圖像描述

約束#2:

在此輸入圖像描述

大小類

已安裝是指安裝大小類,而不是活動 / 非活動

您必須以編程方式創建另一個約束,並激活/停用約束。 這是因為您無法更改約束的乘數( 我可以更改NSLayoutConstraint的乘數屬性嗎? ),也不能修改大小類( activateConstraints:和deactivateConstraints:在IB中創建的約束后不會保持旋轉 )。

有幾種方法可以做到這一點。 在下面的示例中,我使用乘數或1/2創建x1約束的副本。 然后我在兩者之間切換:

@IBOutlet var fullWidthConstraint: NSLayoutConstraint!
var halfWidthConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    halfWidthConstraint = NSLayoutConstraint(item: fullWidthConstraint.firstItem,
        attribute: fullWidthConstraint.firstAttribute,
        relatedBy: fullWidthConstraint.relation,
        toItem: fullWidthConstraint.secondItem,
        attribute: fullWidthConstraint.secondAttribute,
        multiplier: 0.5,
        constant: fullWidthConstraint.constant)
    halfWidthConstraint.priority = fullWidthConstraint.priority
}

@IBAction func changeConstraintAction(sender: UISwitch) {
    if sender.on {
        NSLayoutConstraint.deactivateConstraints([fullWidthConstraint])
        NSLayoutConstraint.activateConstraints([halfWidthConstraint])
    } else {
        NSLayoutConstraint.deactivateConstraints([halfWidthConstraint])
        NSLayoutConstraint.activateConstraints([fullWidthConstraint])
    }
}

iOS 9+Xcode 7+上測試過。

我將描述如何在兩個布局之間進行簡單切換。

當屏幕旋轉時,Autolayout將應用具有更高優先級的已安裝默認布局。 Constraint是否處於活動狀態並不重要。 因為,在旋轉時,會重新安裝故事板上的高優先級布局並且active = true。 因此,即使您更改了活動狀態,也會在旋轉時應用默認布局,並且無法保留任何布局。

切換兩個布局,而不是切換活動狀態。 在兩個布局之間切換時,請使用“優先級”而不是“活動”。 這種方式不需要擔心活動狀態。 這很簡單。

首先,在Storyboard上創建兩個要切換的布局。 檢查兩者是否已安裝。 發生沖突錯誤,因為兩個布局的優先級= 1000(必需)。 將要首先顯示的布局的優先級設置為“高”。 並將其他布局的優先級設置為低,將解決沖突錯誤。 將這些布局的約束關聯為類的IBOutlet。 最后,只需在要更改布局的時間切換高和低之間的優先級。 請注意,請不要將優先級更改為“required”。 優先級設置為必需的布局在此之后無法更改。

class RootViewController: UIViewController {

    @IBOutlet var widthEqualToSuperView: NSLayoutConstraint!
    @IBOutlet var halfWidthOfSuperview: NSLayoutConstraint!

    override func viewDidLayoutSubviews() {
        changeWidth()
    }

    func changeWidth() {
        let orientation = UIApplication.shared.statusBarOrientation
        if (orientation == .portrait || orientation == .portraitUpsideDown) {
            widthEqualToSuperView.priority = UILayoutPriorityDefaultHigh;
            halfWidthOfSuperview.priority = UILayoutPriorityDefaultLow;
        }
        else {
            widthEqualToSuperView.priority = UILayoutPriorityDefaultLow;
            halfWidthOfSuperview.priority = UILayoutPriorityDefaultHigh;
        }
    }

}

全寬的肖像 肖像 半寬景觀 景觀

您可以使用IB為大小類創建的約束進行必要的切換。 訣竅是將折疊狀態保持在變量中並更新約束事件中的約束以及特征集合更改事件。

var collapsed: Bool {
    didSet {
        view.setNeedsUpdateConstraints()
    }
}

@IBAction func onButtonClick(sender: UISwitch) {
    view.layoutIfNeeded()
    collapsed = !collapsed        
    UIView.animate(withDuration: 0.3) {
        view.layoutIfNeeded()
    }
}

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    view.setNeedsUpdateConstraints()
}

override func updateViewConstraints() {
    constraint1.isActive = !collapsed
    constraint2.isActive = collapsed
    super.updateViewConstraints()
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM