xcode 在Swift中设置约束的动画

wljmcqd8  于 2023-05-19  发布在  Swift
关注(0)|答案(7)|浏览(196)

我有一个UITextField,我想扩大其宽度时,点击。我设置了约束,并确保左侧的约束具有较低的优先级,然后我试图在右侧设置动画。
下面是我尝试使用的代码。

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

这是有效的,但它似乎只是立即发生,似乎没有任何运动。我试着把它设置为10秒,以确保我没有错过任何东西,但我得到了同样的结果。
nameInputConstraint是一个约束的名称,我控制它从IB拖到我的类中。

sr4lhrrt

sr4lhrrt1#

需要先更改约束,然后设置更新的动画。
这个应该在监控室里

self.nameInputConstraint.constant = 8

Swift 2

UIView.animateWithDuration(0.5) {
    self.view.layoutIfNeeded()
}

Swift 3,4,5

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

vqlkdk9b2#

SWIFT 4及以上版本:

self.mConstraint.constant = 100.0
UIView.animate(withDuration: 0.3) {
        self.view.layoutIfNeeded()
}

完成示例:

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

lztngnrs3#

需要指出的是,view.layoutIfNeeded()只适用于视图子视图。
因此,要设置视图约束的动画,必须在view-to-animatesuperview上调用它,如下所示:

topConstraint.constant = heightShift

    UIView.animate(withDuration: 0.3) {

        // request layout on the *superview*
        self.view.superview?.layoutIfNeeded()
    }

简单布局的示例如下所示:

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()
        }
    }
}
6vl6ewon

6vl6ewon4#

使用Swift 5和iOS 12.3,根据您的需求,您可以选择以下3种方式之一来解决您的问题。

#1.使用UIViewanimate(withDuration:animations:)类方法

animate(withDuration:animations:)有以下声明:
使用指定的持续时间对一个或多个视图的更改制作动画。

class func animate(withDuration duration: TimeInterval, animations: @escaping () -> Void)

下面的Playground代码显示了animate(withDuration:animations:)的一个可能实现,以便为自动布局约束的不断更改设置动画。

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()

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

init(duration:curve:animations:)有以下声明:
使用内置的UIKit计时曲线初始化动画制作器。

convenience init(duration: TimeInterval, curve: UIViewAnimationCurve, animations: (() -> Void)? = nil)

下面的Playground代码显示了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()

#3.使用UIViewPropertyAnimatorrunningPropertyAnimator(withDuration:delay:options:animations:completion:)类方法

runningPropertyAnimator(withDuration:delay:options:animations:completion:)有以下声明:
创建并返回立即开始运行其动画的animator对象。

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

下面的Playground代码显示了runningPropertyAnimator(withDuration:delay:options:animations:completion:)的一个可能实现,以便为自动布局约束的不断更改设置动画。

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()
rggaifut

rggaifut5#

在我的例子中,我只更新了自定义视图。

// 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()
}
oipij1gg

oipij1gg6#

我想分享我的解决方案,在我不工作的情况下,我的约束设计如下

view1WidthLayout = NSLayoutConstraint(item: view1,
                                      attribute: .width,
                                      relatedBy: .equal,
                                      toItem: nil,
                                      attribute: .width,
                                      multiplier: 1,
                                      constant: 20)

每当我试图在动画之前设置常量时

view1WidthLayout.constant += 20

它立即设置,所以它没有为我工作。
我将约束属性的定义更改为

view1WidthLayout = view1.widthAnchor.constraint(equalToConstant: 20)

那我就成功了

5ktev3wc

5ktev3wc7#

观看this
视频中说,你只需要像下面这样添加self.view.layoutIfNeeded()

UIView.animate(withDuration: 1.0, animations: {
       self.centerX.constant -= 75
       self.view.layoutIfNeeded()
}, completion: nil)

相关问题