使用CAMediaTimingFunction来动画化UIView的NSLayoutConstraint

4

我目前正在一个动画块内对我的约束进行动画化,但是我希望自定义动画类型,它进一步提供了由预设UIVIewAnimationOptions所给出的选项之外的内容。

    UIView.animateWithDuration(2.0, delay: 0.3, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in

        self.heightTransition.constant = self.view.bounds.height - 52
        self.view.layoutIfNeeded()

        }, completion: { (complete) -> Void in
    })

我研究了使用CAMediaTimingFunction的潜力,如此例所示(http://cubic-bezier.com/#.44,.94,.79,-0.01),您可以传入值来改变动画风格。那么我的问题是,在对UIView约束进行动画处理时,我该如何应用CAMediaTimingFunction

你有没有找到解决办法? - Chris
1个回答

1

我不知道是否可以直接实现,因为NSLayoutConstraint是UIKit的一部分,而CALayer是Core Animation的一部分。但对我来说,这种方法可行,我使用自定义三次贝塞尔动画曲线来进行CABasicAnimation,然后在完成时,UIView返回到动画开始之前由其约束定义的起始位置(或者我可以在动画完成块中设置其他约束到我的UIView),如果你想玩一下,可以将以下内容粘贴到空的新项目中:

        import UIKit
    class ViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            super.view.backgroundColor = .white
//Button to trigger animation.
            let button: UIButton = {
                let button = UIButton()
                super.view.addSubview(button)
                button.setTitleColor(UIColor.systemCyan, for: .normal)
                button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
                button.setTitle("Animate!", for: .normal)
                button.translatesAutoresizingMaskIntoConstraints = false
                NSLayoutConstraint.activate([
                    button.topAnchor.constraint(equalTo: super.view.topAnchor, constant: super.view.frame.height * 0.886),
                    button.centerXAnchor.constraint(equalTo: super.view.centerXAnchor),
                    button.heightAnchor.constraint(equalToConstant: super.view.frame.height * 0.024),
                ])
                return button
            }()
        }
        @objc func buttonPressed() {
            //Remove view created previous button press.
            for view in super.view.subviews {
                if view.backgroundColor == .systemMint {
                    view.removeFromSuperview()
                }
            }
            //heightConstraint is distance we want to walk from start to finish of animation.
            var heightConstraint: NSLayoutConstraint!
            var topConstraint: NSLayoutConstraint!
            let view: UIView = {
                let view = UIView()
                super.view.addSubview(view)
                view.translatesAutoresizingMaskIntoConstraints = false
                view.layer.masksToBounds = true
                view.backgroundColor = .systemMint
                //After animation completion view will return to this constraints.
                heightConstraint = view.heightAnchor.constraint(equalToConstant: super.view.frame.height * 0.605)
                topConstraint = view.topAnchor.constraint(equalTo: super.view.topAnchor, constant: -600)
                NSLayoutConstraint.activate([
                    topConstraint,
                    view.widthAnchor.constraint(equalToConstant: super.view.frame.width * 0.87),
                    heightConstraint,
                    view.centerXAnchor.constraint(equalTo: super.view.centerXAnchor)
                ])
                view.layer.cornerRadius = super.view.frame.height * 0.0495
                return view
            }()
            //Create custom animation curve based on cubic bezier controlPoints
            let timingFunction = CAMediaTimingFunction(controlPoints: 0,1.07,0.15,0.97 /*0,1,0,1*/)
            //We can't animate our topConstraint directly, so we'll use "position.y"
            let animation = CABasicAnimation(keyPath: "position.y")
            animation.duration = 3
            //position.y counted from midY, so we have to subtract half of view's height
            //so view's bottom == superview's top is our starting point
            animation.fromValue = -heightConstraint.constant/2
            //and so with finish point
            animation.toValue = heightConstraint.constant/2
            animation.timingFunction = timingFunction
            animation.fillMode = .forwards
            animation.isRemovedOnCompletion = true
            CATransaction.setCompletionBlock({
                /*Here set necessary constraints manually,
                 on completion the will be applied.
                 (Early we set this constraint to -600, so when animation
                 finished - our UIView returns to it's position
                 before animation started, preserving constraints.
                 We can set it to 0 here, or we could do it earlier
                 instead of -600, depends of what we need.)*/
                topConstraint.constant = 0
                        })
            view.layer.add(animation, forKey: nil)
        }
    }

我们可以从gif中看到,在动画完成后,设置给UIView的约束得以保留。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接