尝试在swift中设置约束动画

ice*_*omo 225 xcode constraints swift xcode6

我有一个UITextField,我想在点击时放大它的宽度.我设置了约束,并确保左边的约束优先级低于我试图在右边设置动画的约束.

这是我尝试使用的代码.

  // move the input box
    UIView.animateWithDuration(10.5, animations: {
        self.nameInputConstraint.constant = 8
        }, completion: {
            (value: Bool) in
            println(">>> move const")
    })
Run Code Online (Sandbox Code Playgroud)

这有效,但它似乎只是瞬间发生,似乎没有任何动作.我试着设置它10秒钟以确保我没有遗漏任何东西,但我得到了相同的结果.

nameInputConstraint是我控制拖动以从IB连接到我的类的约束的名称.

感谢您的帮助!

Mun*_*ndi 621

您需要先更改约束,然后为更新设置动画.

self.nameInputConstraint.constant = 8
Run Code Online (Sandbox Code Playgroud)

在Swift 3.0中:

UIView.animateWithDuration(0.5) {
    self.view.layoutIfNeeded()
}
Run Code Online (Sandbox Code Playgroud)

  • 我花了一个小时注意到,我必须在superview上调用layoutIfNeeded ... (9认同)
  • 您提到的动画API用于为视图和图层的*属性*设置动画.在这里,我们需要为布局*中的*更改设置动画.这就是改变布局约束的常量所要求的 - 单独改变常量什么都不做. (3认同)
  • 有人可以解释这是如何/为什么吗?在任何UIView上调用animationWithDuration可以使从UIView继承并更改物理值的任何类产生动画效果吗? (2认同)
  • @Jacky也许你在使用Objective-C推理时误解了强弱变量.Swift闭包是不同的:一旦闭合完成,就没有对象保持闭合中使用的`self`. (2认同)
  • 在我的情况下不起作用,首先发生,该怎么办 (2认同)

Had*_*šić 23

SWIFT 4.x:

self.mConstraint.constant = 100.0
UIView.animate(withDuration: 0.3) {
        self.view.layoutIfNeeded()
}
Run Code Online (Sandbox Code Playgroud)

完成示例:

self.mConstraint.constant = 100
UIView.animate(withDuration: 0.3, animations: {
        self.view.layoutIfNeeded()
    }, completion: {res in
        //Do something
})
Run Code Online (Sandbox Code Playgroud)

  • 它不起作用我已经完成了这个UIView.animate(withDuration:10,delay:0,options:.curveEaseInOut,animations:{self.leftViewHeightConstraint.constant = 200 self.leftView.layoutIfNeeded()},completion:nil) (2认同)
  • 您必须更改约束并*然后*设置动画。 (2认同)

Sté*_*uca 12

指出view.layoutIfNeeded()仅适用于视图子视图非常重要。

因此,要为视图约束设置动画,在视图到动画超级视图上按如下所示调用它很重要:

    topConstraint.constant = heightShift

    UIView.animate(withDuration: 0.3) {

        // request layout on the *superview*
        self.view.superview?.layoutIfNeeded()
    }
Run Code Online (Sandbox Code Playgroud)

一个简单布局的示例如下:

class MyClass {

    /// Container view
    let container = UIView()
        /// View attached to container
        let view = UIView()

    /// Top constraint to animate
    var topConstraint = NSLayoutConstraint()


    /// Create the UI hierarchy and constraints
    func createUI() {
        container.addSubview(view)

        // Create the top constraint
        topConstraint = view.topAnchor.constraint(equalTo: container.topAnchor, constant: 0)


        view.translatesAutoresizingMaskIntoConstraints = false

        // Activate constaint(s)
        NSLayoutConstraint.activate([
           topConstraint,
        ])
    }

    /// Update view constraint with animation
    func updateConstraint(heightShift: CGFloat) {
        topConstraint.constant = heightShift

        UIView.animate(withDuration: 0.3) {

            // request layout on the *superview*
            self.view.superview?.layoutIfNeeded()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这确实是正确的答案。如果您不在超级视图上调用它,您的视图只会跳转到新位置。这是一个非常重要的区别。 (2认同)
  • 这应该是一个正确的答案,我花了一整夜的时间来修复它,谢谢!至少今晚我可以睡觉了。 (2认同)

Ima*_*tit 8

使用Swift 4.1和iOS 11,根据您的需要,您可以选择以下3种方法之一来解决您的问题.


#1.使用UIView's animate(withDuration:animations:)类方法

animate(withDuration:animations:) 有以下声明:

使用指定的持续时间对一个或多个视图进行动画更改.

class func animate(withDuration duration: TimeInterval, animations: @escaping () -> Void)
Run Code Online (Sandbox Code Playgroud)

下面的Playground代码显示了可能的实现,animate(withDuration:animations:)以便为Auto Layout约束的常量更改设置动画.

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let textView = UITextView()
    lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50)

    override func viewDidLoad() {
        view.backgroundColor = .white
        view.addSubview(textView)

        textView.backgroundColor = .orange
        textView.isEditable = false
        textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.topAnchor.constraint(equalToSystemSpacingBelow: view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
        heightConstraint.isActive = true

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:)))
        textView.addGestureRecognizer(tapGesture)
    }

    @objc func doIt(_ sender: UITapGestureRecognizer) {
        heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50
        UIView.animate(withDuration: 2) {
            self.view.layoutIfNeeded()
        }
    }

}

PlaygroundPage.current.liveView = ViewController()
Run Code Online (Sandbox Code Playgroud)

#2.使用UIViewPropertyAnimatorinit(duration:curve:animations:)初始化和startAnimation()方法

init(duration:curve:animations:) 有以下声明:

使用内置的UIKit时序曲线初始化动画师.

convenience init(duration: TimeInterval, curve: UIViewAnimationCurve, animations: (() -> Void)? = nil)
Run Code Online (Sandbox Code Playgroud)

下面的游乐场代码显示了一个可能实现的init(duration:curve:animations:),并startAnimation()以动画的自动布局约束的不断变化.

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let textView = UITextView()
    lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50)

    override func viewDidLoad() {
        view.backgroundColor = .white
        view.addSubview(textView)

        textView.backgroundColor = .orange
        textView.isEditable = false
        textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.topAnchor.constraint(equalToSystemSpacingBelow: view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
        heightConstraint.isActive = true

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:)))
        textView.addGestureRecognizer(tapGesture)
    }

    @objc func doIt(_ sender: UITapGestureRecognizer) {
        heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50
        let animator = UIViewPropertyAnimator(duration: 2, curve: .linear, animations: {
            self.view.layoutIfNeeded()
        })
        animator.startAnimation()
    }

}

PlaygroundPage.current.liveView = ViewController()
Run Code Online (Sandbox Code Playgroud)

#3.使用UIViewPropertyAnimator's runningPropertyAnimator(withDuration:delay:options:animations:completion:)类方法

runningPropertyAnimator(withDuration:delay:options:animations:completion:) 有以下声明:

创建并返回一个动画对象,该对象立即开始运行其动画.

class func runningPropertyAnimator(withDuration duration: TimeInterval, delay: TimeInterval, options: UIViewAnimationOptions = [], animations: @escaping () -> Void, completion: ((UIViewAnimatingPosition) -> Void)? = nil) -> Self
Run Code Online (Sandbox Code Playgroud)

下面的Playground代码显示了可能的实现,runningPropertyAnimator(withDuration:delay:options:animations:completion:)以便为Auto Layout约束的常量更改设置动画.

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let textView = UITextView()
    lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50)

    override func viewDidLoad() {
        view.backgroundColor = .white
        view.addSubview(textView)

        textView.backgroundColor = .orange
        textView.isEditable = false
        textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.topAnchor.constraint(equalToSystemSpacingBelow: view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
        heightConstraint.isActive = true

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:)))
        textView.addGestureRecognizer(tapGesture)
    }

    @objc func doIt(_ sender: UITapGestureRecognizer) {
        heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50
        UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 2, delay: 0, options: [], animations: {
            self.view.layoutIfNeeded()
        })
    }

}

PlaygroundPage.current.liveView = ViewController()
Run Code Online (Sandbox Code Playgroud)


Den*_*Den 7

就我而言,我只更新了自定义视图。

// DO NOT LIKE THIS
customView.layoutIfNeeded()    // Change to view.layoutIfNeeded()
UIView.animate(withDuration: 0.5) {
   customViewConstraint.constant = 100.0
   customView.layoutIfNeeded() // Change to view.layoutIfNeeded()
}
Run Code Online (Sandbox Code Playgroud)