动画Uibutton配置更改

发布于 2025-01-20 17:27:49 字数 743 浏览 0 评论 0原文

现代 UIButton 配置 API 允许新设置按钮外观的方式。然而,下面的代码完全跳过动画。

@IBAction func buttonTouched(_ sender: UIButton) {
    sender.configuration?.background.backgroundColor = .green
    UIView.animate(withDuration: 0.4, delay: 0.5) {
        sender.configuration?.background.backgroundColor = .systemMint
    }  
}

类似的事情可以这样完成:

@IBAction func buttonTouched(_ sender: UIButton) {
    sender.backgroundColor = .red
    UIView.animate(withDuration: 0.4, delay: 0.5) {
        sender.backgroundColor = .systemMint
    }
}

这有效。问题是如何为 UIButton 的配置更改设置动画。

Modern UIButton configuration API allows for new way of setting button appearance. However the code below skips the animation entirely.

@IBAction func buttonTouched(_ sender: UIButton) {
    sender.configuration?.background.backgroundColor = .green
    UIView.animate(withDuration: 0.4, delay: 0.5) {
        sender.configuration?.background.backgroundColor = .systemMint
    }  
}

Similar thing can be done like this:

@IBAction func buttonTouched(_ sender: UIButton) {
    sender.backgroundColor = .red
    UIView.animate(withDuration: 0.4, delay: 0.5) {
        sender.backgroundColor = .systemMint
    }
}

And this works. The question is how to animate UIButton's configuration changes.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

尛丟丟 2025-01-27 17:27:49

快速搜索后,它将出现configuration.background.backgroundcolor不是 andimable。

根据您的需求,您可以使用.customview对按钮的背景使用,然后为该视图对颜色更改进行动画。

快速示例(假设您已将按钮添加为@iboutlet):

class TestVC: UIViewController {

    @IBOutlet var button: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let v = UIView()
        v.backgroundColor = .red
        button.configuration?.background.customView = v
        
    }
    
    @IBAction func buttonTouched(_ sender: UIButton) {
        if let v = sender.configuration?.background.customView {
            UIView.animate(withDuration: 0.4, delay: 0.5) {
                v.backgroundColor = v.backgroundColor == .red ? .systemMint : .red
            }
        }
    }
}

After some quick searching, it appears configuration.background.backgroundColor is not animatable.

Depending on your needs, you can use a .customView for the button's background and then animate the color change for that view.

Quick example (assuming you've added the button as an @IBOutlet):

class TestVC: UIViewController {

    @IBOutlet var button: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let v = UIView()
        v.backgroundColor = .red
        button.configuration?.background.customView = v
        
    }
    
    @IBAction func buttonTouched(_ sender: UIButton) {
        if let v = sender.configuration?.background.customView {
            UIView.animate(withDuration: 0.4, delay: 0.5) {
                v.backgroundColor = v.backgroundColor == .red ? .systemMint : .red
            }
        }
    }
}
白馒头 2025-01-27 17:27:49

通过使用过渡来实现动画配置更改的方法是迄今为止我能找到的唯一解决方法。有点像这样:

@IBAction func buttonTouched(_ sender: UIButton) {
    UIView.transition(with: sender, duration: 0.3, options: .transitionCrossDissolve) {
        sender.configuration?.background.backgroundColor = .red
    } completion: { _ in
        UIView.transition(with: sender, duration: 1.0, options: .transitionCrossDissolve) {
            sender.configuration?.background.backgroundColor = .cyan
        }
    }
}

当我尝试优化和重用代码时,我得到了类似的结果:

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Another option is subclass `UIButton` and override its `configurationUpdateHandler`
        view.subviews.compactMap({ $0 as? UIButton }).forEach {
            $0.configurationUpdateHandler = { button in
                guard let config = button.configuration else { return }
                button.setConfiguration(config,duration: 2)
            }
        }
    }

    @IBAction func buttonTouched(_ sender: UIButton) {
//        sender.configuration?.background.backgroundColor = .red
//        sender.configuration?.baseForegroundColor = .white
//        The above would work, but we should rather aggregate all changes at once.
        if var config = sender.configuration {
            config.background.backgroundColor = .red
            config.baseForegroundColor = .white
            sender.configuration = config
        }
        
    }
    
}

extension UIButton {
    func setConfiguration(_ configuration: UIButton.Configuration, duration: Double = 0.25, completion: ((Bool) -> Void)? = nil) {
        UIView.transition(with: self, duration: duration, options: .transitionCrossDissolve) {
            self.configuration? = configuration
        } completion: { completion?($0) }
    }
}
 I

The way to achieve animated configuration change by using transitions is the only workaround I could find so far. Somewhat like this:

@IBAction func buttonTouched(_ sender: UIButton) {
    UIView.transition(with: sender, duration: 0.3, options: .transitionCrossDissolve) {
        sender.configuration?.background.backgroundColor = .red
    } completion: { _ in
        UIView.transition(with: sender, duration: 1.0, options: .transitionCrossDissolve) {
            sender.configuration?.background.backgroundColor = .cyan
        }
    }
}

When I tried to optimize and reuse code, I ended with something like:

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Another option is subclass `UIButton` and override its `configurationUpdateHandler`
        view.subviews.compactMap({ $0 as? UIButton }).forEach {
            $0.configurationUpdateHandler = { button in
                guard let config = button.configuration else { return }
                button.setConfiguration(config,duration: 2)
            }
        }
    }

    @IBAction func buttonTouched(_ sender: UIButton) {
//        sender.configuration?.background.backgroundColor = .red
//        sender.configuration?.baseForegroundColor = .white
//        The above would work, but we should rather aggregate all changes at once.
        if var config = sender.configuration {
            config.background.backgroundColor = .red
            config.baseForegroundColor = .white
            sender.configuration = config
        }
        
    }
    
}

extension UIButton {
    func setConfiguration(_ configuration: UIButton.Configuration, duration: Double = 0.25, completion: ((Bool) -> Void)? = nil) {
        UIView.transition(with: self, duration: duration, options: .transitionCrossDissolve) {
            self.configuration? = configuration
        } completion: { completion?($0) }
    }
}
 I
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文