ios - 在 Swift 中呈现旋转器的动画按钮

标签 ios swift animation uibutton uianimation

所以我想让一个按钮在按下时有动画效果以转到一个圆圈,然后能够将按钮发送回其原始状态。这是我当前的动画,正如您所看到的,我已经完成了一半。

GIF showing how the animation is currently working

正如您所见,我在这里遇到了多个问题。首先,当我设置新约束时,X 约束不会将圆放置在父 View 的中间。然后我最初的想法是,当我调用重置函数时,我也会传递 View 的原始约束,但这不起作用。

我的想法是,当我使用它时,我将放置一个 UIView,然后在该 View 中放置按钮,这样我就可以操纵它的约束。如果我在 UIStackView 中放置一个按钮,情况也会如此。

这是我的代码,任何输入都很棒

extension UIButton {

func animateWhileAwaitingResponse(showLoading: Bool, originalConstraints: [NSLayoutConstraint]) {

    let spinner = UIActivityIndicatorView()
    let constraints = [
        NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: self.superview, attribute: .centerX, multiplier: 1, constant: 0),
        NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 45),
        NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 45),
        NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: self.superview, attribute: .top, multiplier: 1, constant: 4),
        NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: self.superview, attribute: .bottom, multiplier: 1, constant: 8),
        NSLayoutConstraint(item: spinner, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0),
        NSLayoutConstraint(item: spinner, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0),
        NSLayoutConstraint(item: spinner, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 45),
        NSLayoutConstraint(item: spinner, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 45)
    ]

    if showLoading {

        NSLayoutConstraint.deactivate(self.constraints)
        self.translatesAutoresizingMaskIntoConstraints = false
        spinner.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(spinner)
        self.superview?.addConstraints(constraints)
        spinner.color = .white
        spinner.startAnimating()

        UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
            self.setTitleColor(.clear, for: .normal)
            self.layer.cornerRadius = 22.5
            self.layoutIfNeeded()
        }, completion: nil)
    } else {
        UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
            NSLayoutConstraint.deactivate(self.constraints)
            self.setTitleColor(.white, for: .normal)
            self.superview?.addConstraints(originalConstraints)
            NSLayoutConstraint.activate(originalConstraints)
            self.layer.cornerRadius = 0

            for subview in self.subviews where subview is UIActivityIndicatorView {
                subview.removeFromSuperview()
            }
            self.layoutIfNeeded()
        }, completion: nil)

      }
   }
}

最佳答案

我已按如下方式更新了您的按钮扩展代码,即添加和删除动画约束。

extension UIButton {

    func animateWhileAwaitingResponse(showLoading: Bool, originalConstraints: [NSLayoutConstraint]) {

        let spinner = UIActivityIndicatorView()
        spinner.isUserInteractionEnabled = false

        // Constraints which will add in supper view
        let constraints = [
            NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: self.superview, attribute: .centerX, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: self, attribute: .centerY, relatedBy: .equal, toItem: self.superview, attribute: .centerY, multiplier: 1, constant: 0),

            NSLayoutConstraint(item: spinner, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: spinner, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: spinner, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 45),
            NSLayoutConstraint(item: spinner, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 45)
        ]

        // Constrains which will add in button
        let selfCostraints = [
            NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: 45),
            NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 45),
        ]

        // Keeping this outside of condition due to adding constrains programatically.
        self.translatesAutoresizingMaskIntoConstraints = false
        spinner.translatesAutoresizingMaskIntoConstraints = false

        if showLoading {

            // Remove width constrains of button from superview
            // Identifier given in storyboard constrains
            self.superview?.constraints.forEach({ (constraint) in
                if constraint.identifier == "buttonWidth" {
                    constraint.isActive = false
                }
            })

            NSLayoutConstraint.deactivate(self.constraints)

            self.addSubview(spinner)
            self.superview?.addConstraints(constraints)
            self.addConstraints(selfCostraints)
            spinner.color = .white
            spinner.startAnimating()
            spinner.alpha = 0

            UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
                self.setTitleColor(.clear, for: .normal)
                self.layer.cornerRadius = 22.5
                spinner.alpha = 1
                self.layoutIfNeeded()
            }, completion: nil)

        } else {


            UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {

                for subview in self.subviews where subview is UIActivityIndicatorView {
                    subview.removeFromSuperview()
                }

                self.removeConstraints(selfCostraints)
                NSLayoutConstraint.deactivate(self.constraints)
                self.setTitleColor(.white, for: .normal)
                self.superview?.addConstraints(originalConstraints)
                NSLayoutConstraint.activate(originalConstraints)
                self.layer.cornerRadius = 0

                self.layoutIfNeeded()
            }, completion: nil)
        }
    }
} 

我向按钮添加了以下约束:

Button Constrains

此外,还添加了按钮宽度约束的标识符以从 super 中删除,这将增加原始约束的运行时间。

Width Constrains

然后我通过宽度约束的导出以编程方式更改按钮的宽度:

@IBOutlet weak var const_btnAnimation_width : NSLayoutConstraint!

viewDidLoad 方法内部

self.const_btnAnimation_width.constant = UIScreen.main.bounds.width - 40

其中 40 是前导空格和尾随空格的总和。

点击按钮

@IBAction func btnAnimationPressed(_ sender: UIButton) {

    sender.isSelected = !sender.isSelected

    if sender.isSelected {
        self.btnAnimation.animateWhileAwaitingResponse(showLoading: true, originalConstraints: sender.constraints)
    } else {
        self.btnAnimation.animateWhileAwaitingResponse(showLoading: false, originalConstraints: self.btnAnimationConstraints)
    }
}

btnAnimationConstraintsNSLayoutConstraint 的数组,如下所示:

var btnAnimationConstraints = [NSLayoutConstraint]()

所以我只是在 viewDidAppear 方法中分配按钮的所有约束,如下所示:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    self.btnAnimationConstraints = self.btnAnimation.constraints
}

希望这对您有帮助。

输出:

Button Animation

关于ios - 在 Swift 中呈现旋转器的动画按钮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57897375/

相关文章:

ios - 设置委托(delegate)以将数据从一个选项卡传递到另一个选项卡

android - 禁用 ViewPager 滚动动画

ios - 错误域=NSCocoaErrorDomain 代码=256 "The file “images” 无法打开。"UserInfo={NSURL=http ://

python - 如何动画matplotlib函数优化?

python - 使用 matplotlib 动画波脉冲

ios - CFNetwork 内部错误 : URLConnectionLoader. cpp:289

iOS 如何为 api presentviewcontroller 和 dissmissviewcontroller 制作更慢的动画?

ios - Swift 延迟在 AppDelegate 中设置 rootViewController

swift - 结构变量用setter初始化

swift - 在界面生成器的 SKScene 中隐藏节点