iOS 如何动画改变约束

6,654 阅读1分钟

当我们使用 frame 布局控件的时候,如果控件的 frame 发生改变时,我们想让改变产生动画过渡效果,而不是生硬的直接改变。我们可以使用 UIView 的 animate(withDuration:animations:completion:) 函数来实现,如下面的代码:

UIView.animate(withDuration: 0.5) {
     // 改变后的frame
    self.exampleView.frame = CGRect(x: 10, y: 10, width: 100, height: 100)
}

那当我们使用 AutoLayout 布局的时候,我们想实现上面的效果该如何写呢?

通过下面的两个步骤我们就可以实现:

  • 改变目标控件约束
  • 调用 animate(withDuration:animations:completion:) 函数
    • 调用目标控件父视图的 layoutIfNeeded() 函数

具体例子

声明全局变量

private let exampleView = UIView(frame: .zero)
private var topConstraint = NSLayoutConstraint()

使用 AutoLayout 布局控件

extension ViewController {
    private func setupSubviews() {
        
        exampleView.backgroundColor = .green
        view.addSubview(exampleView)
        
        exampleView.translatesAutoresizingMaskIntoConstraints = false
        topConstraint = exampleView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100)
        topConstraint.constant = 100
        NSLayoutConstraint.activate([
            topConstraint,
            exampleView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 100),
            exampleView.widthAnchor.constraint(equalToConstant: 100),
            exampleView.heightAnchor.constraint(equalToConstant: 100)
            ])
        
        let button = UIButton(type: .custom)
        button.frame = CGRect(x: 100, y: 400, width: 100, height: 50)
        button.backgroundColor = .red
        button.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)
        view.addSubview(button)
    }
}

动画改变约束

extension ViewController {
    @objc func buttonAction(_ sender: UIButton) {
        // 修改约束
        topConstraint.constant = 200
        //调用父视图的 layoutIfNeeded()
        UIView.animate(withDuration: 0.5) {
            self.view.layoutIfNeeded()
        }
    }
}

效果图 - 动画改变约束

注意事项

  • 在要调用目标控件的父视图layoutIfNeeded() 函数
  • 注意调用的是 layoutIfNeeded() 函数,不是 setNeedsLayout()
  • 参考