【问题标题】:why NSLayoutConstraint animation works only one time?为什么 NSLayoutConstraint 动画只能工作一次?
【发布时间】:2020-06-22 01:08:42
【问题描述】:

在我的项目中,我有一个 someView(UIView 类型),在 holderView(UIView 类型)内部。 someView 有 2 个状态。 在状态 1 中 someView 变大,在第 2 步中 someView 变小。 当某些条件正确时, someView 显示在状态 1 中,当它不是 someView 时显示在状态 2 中。 我想用动画来做到这一点,我在我的项目中使用 NSLayoutConstraint。我正在使用此代码(someViewHeight 和 someViewWidth 的类型为 NSLayoutConstraint):

func minimizeSomeView() {
    someViewHeight.constant = holderView.frame.width
    someViewWidth.constant  = holderView.frame.height

    UIView.animate(withDuration: 1.0) {
        self.view.layoutIfNeeded()
    }
}

func maximizeSomeView() {
    someViewHeight.constant = holderView.frame.width/4
    someViewWidth.constant  = holderView.frame.height/4

    UIView.animate(withDuration: 1.0) {
        self.view.layoutIfNeeded()
    }
}

if someTextField.text != nil {
    minimizeSomeView()
} else. {
    maximizeSomeView()
}

我在 viewDidLayoutSubviews() 中定义了 someViewHeight 和 someViewWidth,这是我的代码:

class ViewController: UIViewController {

    private var holderView, someView: UIView!
    private var someViewHeight,someViewWidth: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
    
        super.viewDidLoad()
    
        view.backgroundColor = .white
    
        // Holder View
        holderView = UIView()
        holderView.backgroundColor = .red
        holderView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(holderView)
    
        NSLayoutConstraint.activate([
            holderView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            holderView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            holderView.topAnchor.constraint(equalTo: view.topAnchor, constant: 120),
            holderView.heightAnchor.constraint(equalToConstant: view.frame.height * 40 / 100)
        ])
    
        // Some View
        someView = UIView()
        someView.backgroundColor = .blue
        someView.translatesAutoresizingMaskIntoConstraints = false
        holderView.addSubview(someView)
    
        someView.topAnchor.constraint(equalTo: holderView.topAnchor).isActive = true
        someView.trailingAnchor.constraint(equalTo: holderView.trailingAnchor).isActive = true
    
        // Some TextField
        let someTextField = UITextField()
        someTextField.backgroundColor = .yellow
        someTextField.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(someTextField)
    
        NSLayoutConstraint.activate([
            someTextField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            someTextField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            someTextField.topAnchor.constraint(equalTo: view.bottomAnchor, constant: -100),
            someTextField.heightAnchor.constraint(equalToConstant: 50)
        ])
    
        someTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
    }


    override func viewDidLayoutSubviews() {
    
        someViewHeight = someView.heightAnchor.constraint(equalToConstant: holderView.frame.width)
        someViewHeight.isActive = true
        someViewWidth = someView.widthAnchor.constraint(equalToConstant: holderView.frame.width)
        someViewWidth.isActive = true
    }

    func minimizeSomeView() {
    
        someViewHeight.constant = holderView.frame.width/4
        someViewWidth.constant  = holderView.frame.height/4
    
        UIView.animate(withDuration: 1.0) {
            self.view.layoutIfNeeded()
        }
    }

    func maximizeSomeView() {
    
        someViewHeight.constant = holderView.frame.width
        someViewWidth.constant  = holderView.frame.height
    
        UIView.animate(withDuration: 1.0) {
            self.view.layoutIfNeeded()
        }
    }

    @objc func textFieldDidChange(_ textfield: UITextField) {

        if textfield.text!.count > 0 {
            self.minimizeSomeView()
        } else {
            self.maximizeSomeView()
        }
    }
}

【问题讨论】:

    标签: swift animation nslayoutconstraint


    【解决方案1】:

    您不应该更新viewDidLayoutSubviews 中的约束,尤其是在您使用自动布局时。你不需要这个块

    当您添加约束时,您可以初始化并使其处于活动状态。 在这里,我们可以按比例指定约束。即someView 的高度是holderView 的 0.4。同样,someView 的宽度是holderView 的 0.4。

    1. 要解决此问题,您可以执行以下更改

    // 你的一些视图约束

        someView.topAnchor.constraint(equalTo: holderView.topAnchor).isActive = true
        someView.trailingAnchor.constraint(equalTo: holderView.trailingAnchor).isActive = true
        maximizeSomeView()
    
    1. 移除 viewDidLayouSubView 代码

    2. 更新您的最大化和最小化事件。在这里我必须删除现有的约束,因为.multiplier 是一个只读属性。

    func  minimizeSomeView() {
    
    removeExistingConstriant()
    
    UIView.animate(withDuration: 1.0) { [unowned self] in
    
    self.someViewWidth = self.someView.widthAnchor.constraint(equalTo: self.holderView.widthAnchor, multiplier: 1.0)
    
    self.someViewWidth.isActive = true
    
    self.someViewHeight = self.someView.heightAnchor.constraint(equalTo:
    self.holderView.heightAnchor, multiplier: 1.0)
    
    self.someViewHeight.isActive = true
    
    self.view.layoutIfNeeded()
    
    }
    
    }
    
    func  maximizeSomeView() {
    
    removeExistingConstriant()
    
    UIView.animate(withDuration: 1.0) { [unowned self] in
    
    self.someViewWidth = self.someView.widthAnchor.constraint(equalTo: self.holderView.widthAnchor, multiplier: 0.4)
    
    self.someViewWidth.isActive = true
    
    self.someViewHeight = self.someView.heightAnchor.constraint(equalTo:
    self.holderView.heightAnchor, multiplier: 0.4)
    
    self.someViewHeight.isActive = true
    
    self.view.layoutIfNeeded()
    
    }
    
    }
    
    func  removeExistingConstriant(){
    
    if  self.someViewHeight  !=  nil {
    
    self.someViewHeight.isActive = false
    
    }
    
    if  self.someViewWidth  !=  nil {
    
    self.someViewWidth.isActive = false
    
    }
    
    }
    

    【讨论】:

    • someView 第一次没有显示。但是在输入一些文本或从文本字段中删除所有文本后,所有动画都可以正常工作。这是因为 self.holderView.frame.width 在 vi​​ewDidLoad() 中返回 0。
    • 啊我c,你可以用比例来指定约束
    猜你喜欢
    • 1970-01-01
    • 2019-10-08
    • 2016-11-10
    • 2017-09-10
    • 2021-03-30
    • 1970-01-01
    • 2018-05-20
    • 2020-11-12
    • 2021-01-15
    相关资源
    最近更新 更多