LayoutAnchor - ShenYj/ShenYj.github.io GitHub Wiki

NSLayoutAnchor

NSLayoutAnchor 作为 iOS9 的新特性是对AutoLayout创建约束的补充,核心还是 NSLayoutConstraint,可以避免过长创建约束代码

早期一条条创建 NSLayoutConstraint 约束的方式的确太啰嗦,因此绝大部分iOS 开发者应该都是使用 Masonry/SnapKit 或其他成熟的库来实现代码布局

简单的布局,也有使用 NSLayoutAnchor 实现过,不过一直没有研究过更新布局的方式,今天有空,换成原生的API,试一下最常见的两种情形下更新布局的实现

  • 示例代码,每一次点击按钮的时候,更改红色View的宽度

    import UIKit
    
    class ViewController: UIViewController {
        
        private lazy var testButton = {
            let btn = UIButton()
            btn.setTitle("test", for: .normal)
            btn.setTitleColor(.black, for: .normal)
            btn.backgroundColor = UIColor.systemGreen
            btn.layer.cornerRadius = 10
            btn.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner]
            btn.layer.masksToBounds = true
            btn.translatesAutoresizingMaskIntoConstraints = false
            btn.addTarget(self, action: #selector(_target(_:)), for: .touchUpInside)
            return btn
        }()
        
        private lazy var redView = {
            let v = UIView()
            v.backgroundColor = UIColor.systemRed
            v.layer.cornerRadius = 10
            v.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner]
            v.layer.masksToBounds = true
            v.translatesAutoresizingMaskIntoConstraints = false
            return v
        }()
        
        private var feedback: UIImpactFeedbackGenerator?
        
        private var widthAnchorConstrainst: NSLayoutConstraint?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
            // Do any additional setup after loading the view.
            view.backgroundColor = .systemBlue
            view.addSubview(testButton)
            view.addSubview(redView)
            
            NSLayoutConstraint.activate([
                redView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40),
                redView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                redView.heightAnchor.constraint(equalToConstant: 200),
                testButton.topAnchor.constraint(equalTo: redView.bottomAnchor, constant: 40),
                testButton.widthAnchor.constraint(equalToConstant: 120),
                testButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                testButton.heightAnchor.constraint(equalToConstant: 44)
            ])
            
            widthAnchorConstrainst = redView.widthAnchor.constraint(equalToConstant: 200)
            widthAnchorConstrainst?.isActive = true
        }
        
        
        @objc private func _target(_ sender: UIButton) {
            if widthAnchorConstrainst?.constant == 200 {
                widthAnchorConstrainst?.constant = 100
            }
            else {
                widthAnchorConstrainst?.constant = 200
            }
        }
        
    }
  • 示例代码,每一次点击按钮的时候,更改按钮的相对位置

    import UIKit
    
    class ViewController: UIViewController {
        
        private lazy var testButton = {
            let btn = UIButton()
            btn.setTitle("test", for: .normal)
            btn.setTitleColor(.black, for: .normal)
            btn.backgroundColor = UIColor.systemGreen
            btn.layer.cornerRadius = 10
            btn.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner]
            btn.layer.masksToBounds = true
            btn.translatesAutoresizingMaskIntoConstraints = false
            btn.addTarget(self, action: #selector(_target(_:)), for: .touchUpInside)
            return btn
        }()
        
        private lazy var redView = {
            let v = UIView()
            v.backgroundColor = UIColor.systemRed
            v.layer.cornerRadius = 10
            v.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner]
            v.layer.masksToBounds = true
            v.translatesAutoresizingMaskIntoConstraints = false
            return v
        }()
        
        private var feedback: UIImpactFeedbackGenerator?
        
        private var buttonTopConstraint: NSLayoutConstraint?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
            // Do any additional setup after loading the view.
            view.backgroundColor = .systemBlue
            view.addSubview(testButton)
            view.addSubview(redView)
            
            NSLayoutConstraint.activate([
                redView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40),
                redView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                redView.heightAnchor.constraint(equalToConstant: 200),
                redView.widthAnchor.constraint(equalToConstant: 200),
                testButton.widthAnchor.constraint(equalToConstant: 120),
                testButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                testButton.heightAnchor.constraint(equalToConstant: 44)
            ])
            
            buttonTopConstraint = testButton.topAnchor.constraint(equalTo: redView.bottomAnchor, constant: 40)
            buttonTopConstraint?.isActive = true
        }
        
        
        @objc private func _target(_ sender: UIButton) {
            guard let buttonTopConstraint else { return }
            
            if let secondItem = buttonTopConstraint.secondItem as? UIView , secondItem == redView {
                NSLayoutConstraint.deactivate([buttonTopConstraint])
                self.buttonTopConstraint = testButton.topAnchor.constraint(equalTo: view.centerYAnchor, constant: 0)
                self.buttonTopConstraint?.isActive = true
            }
            else {
                NSLayoutConstraint.deactivate([buttonTopConstraint])
                self.buttonTopConstraint = testButton.topAnchor.constraint(equalTo: redView.bottomAnchor, constant: 40)
                self.buttonTopConstraint?.isActive = true
            }
        }
    }
⚠️ **GitHub.com Fallback** ⚠️