Display activity indicator inside UIButton

后端 未结 10 1706
囚心锁ツ
囚心锁ツ 2021-01-31 17:36

I would like to change the content of a UIButton to an ActivityIndicator after it is pressed.

I know buttons have an imageView and a titleLabel, but I don\'t know how to

相关标签:
10条回答
  • 2021-01-31 17:50

    Code found here:

    https://www.snip2code.com/Snippet/777050/iOS---Swift---UIButton-subclass-for-show/

    import UIKit
    
    class LoadingButton: UIButton {
    private var originalButtonText: String?
    var activityIndicator: UIActivityIndicatorView!
    
    func showLoading() {
        originalButtonText = self.titleLabel?.text
        self.setTitle("", for: .normal)
        
        if (activityIndicator == nil) {
            activityIndicator = createActivityIndicator()
        }
        
        showSpinning()
    }
    
    func hideLoading() {
        self.setTitle(originalButtonText, for: .normal)
        activityIndicator.stopAnimating()
    }
    
    private func createActivityIndicator() -> UIActivityIndicatorView {
        let activityIndicator = UIActivityIndicatorView()
        activityIndicator.hidesWhenStopped = true
        activityIndicator.color = .lightGray
        return activityIndicator
    }
    
    private func showSpinning() {
        activityIndicator.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(activityIndicator)
        centerActivityIndicatorInButton()
        activityIndicator.startAnimating()
    }
    
    private func centerActivityIndicatorInButton() {
        let xCenterConstraint = NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: activityIndicator, attribute: .centerX, multiplier: 1, constant: 0)
        self.addConstraint(xCenterConstraint)
        
        let yCenterConstraint = NSLayoutConstraint(item: self, attribute: .centerY, relatedBy: .equal, toItem: activityIndicator, attribute: .centerY, multiplier: 1, constant: 0)
        self.addConstraint(yCenterConstraint)
    }
    }
    
    0 讨论(0)
  • 2021-01-31 17:54

    Excellent @Steve,

    Can use below implementation instead of line,

    var activityIndicator: UIActivityIndicatorView!

    use this, so that if we configure the activity indicator before calling showLoading(), the app wont crash.

    private var _activityIndicator:UIActivityIndicatorView! = nil
    var activityIndicator: UIActivityIndicatorView{
        set{
            _activityIndicator = newValue
    
        }
        get{
            if _activityIndicator == nil{
                _activityIndicator = createActivityIndicator()
            }
            return _activityIndicator
        }
    }
    
    0 讨论(0)
  • 2021-01-31 17:55

    Swift 4.0 with a little modification

    class LoadingUIButton: UIButton {
    
        @IBInspectable var indicatorColor : UIColor = .lightGray
    
        var originalButtonText: String?
        var activityIndicator: UIActivityIndicatorView!
    
        func showLoading() {
            originalButtonText = self.titleLabel?.text
            self.setTitle("", for: .normal)
    
            if (activityIndicator == nil) {
                activityIndicator = createActivityIndicator()
            }
    
            showSpinning()
        }
    
        func hideLoading() {
            DispatchQueue.main.async(execute: {
                self.setTitle(self.originalButtonText, for: .normal)
                self.activityIndicator.stopAnimating()
            })
        }
    
        private func createActivityIndicator() -> UIActivityIndicatorView {
            let activityIndicator = UIActivityIndicatorView()
            activityIndicator.hidesWhenStopped = true
            activityIndicator.color = indicatorColor
            return activityIndicator
        }
    
        private func showSpinning() {
            activityIndicator.translatesAutoresizingMaskIntoConstraints = false
            self.addSubview(activityIndicator)
            centerActivityIndicatorInButton()
            activityIndicator.startAnimating()
        }
    
        private func centerActivityIndicatorInButton() {
            let xCenterConstraint = NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: activityIndicator, attribute: .centerX, multiplier: 1, constant: 0)
            self.addConstraint(xCenterConstraint)
    
            let yCenterConstraint = NSLayoutConstraint(item: self, attribute: .centerY, relatedBy: .equal, toItem: activityIndicator, attribute: .centerY, multiplier: 1, constant: 0)
            self.addConstraint(yCenterConstraint)
        }
    
    }
    
    0 讨论(0)
  • 2021-01-31 18:01

    Here is my edit with little less code.

    class Button: UIButton {
        private var originalButtonText: String?
    
        private lazy var activityIndicator: UIActivityIndicatorView = {
            let activityIndicator = UIActivityIndicatorView()
            activityIndicator.translatesAutoresizingMaskIntoConstraints = false
            activityIndicator.color = .black
            addSubview(activityIndicator)
    
            NSLayoutConstraint.activate([
                activityIndicator.centerYAnchor.constraint(equalTo: self.centerYAnchor),
                activityIndicator.centerXAnchor.constraint(equalTo: self.centerXAnchor)
            ])
    
            return activityIndicator
        }()
    
        func loading(_ isLoading: Bool) {
            isEnabled = !isLoading
    
            if isLoading {
                originalButtonText = titleLabel?.text
                setTitle("", for: .normal)
                activityIndicator.startAnimating()
            } else {
                setTitle(originalButtonText, for: .normal)
                activityIndicator.stopAnimating()
            }
        }
    }
    

    Usage: button.loading(true/false)

    0 讨论(0)
  • 2021-01-31 18:05

    Updated selected answer( steve-rosenberg ) for Apple Swift version 3.0.1 (swiftlang-800.0.58.6 clang-800.0.42.1) Xcode 8.1 (8B62)

    import ObjectiveC
    
    private var originalButtonText: String?
    private var activityIndicator: UIActivityIndicatorView!
    
    extension UIButton{
    
        func showLoading() {
            originalButtonText = self.titleLabel?.text
            self.setTitle("", for: .normal)
    
            if (activityIndicator == nil) {
                activityIndicator = createActivityIndicator()
            }
    
            showSpinning()
        }
    
        func hideLoading() {
            self.setTitle(originalButtonText, for: .normal)
            activityIndicator.stopAnimating()
        }
    
        private func createActivityIndicator() -> UIActivityIndicatorView {
            let activityIndicator = UIActivityIndicatorView()
            activityIndicator.hidesWhenStopped = true
            activityIndicator.color = UIColor.lightGray
            return activityIndicator
        }
    
        func showSpinning() {
            activityIndicator.translatesAutoresizingMaskIntoConstraints = false
            self.addSubview(activityIndicator)
            centerActivityIndicatorInButton()
            activityIndicator.startAnimating()
        }
    
        private func centerActivityIndicatorInButton() {
            let xCenterConstraint = NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: activityIndicator, attribute: .centerX, multiplier: 1, constant: 0)
            self.addConstraint(xCenterConstraint)
    
            let yCenterConstraint = NSLayoutConstraint(item: self, attribute: .centerY, relatedBy: .equal, toItem: activityIndicator, attribute: .centerY, multiplier: 1, constant: 0)
            self.addConstraint(yCenterConstraint)
        }
    }
    
    0 讨论(0)
  • 2021-01-31 18:10

    @Boris: This should not be in an extension.

    Here it is in swift 3/4, with improved code: disables button, works with images and titles.

    class LoadingButton: UIButton {
    
        struct ButtonState {
            var state: UIControlState
            var title: String?
            var image: UIImage?
        }
    
        private (set) var buttonStates: [ButtonState] = []
        private lazy var activityIndicator: UIActivityIndicatorView = {
            let activityIndicator = UIActivityIndicatorView()
            activityIndicator.hidesWhenStopped = true
            activityIndicator.color = self.titleColor(for: .normal)
            self.addSubview(activityIndicator)
            activityIndicator.translatesAutoresizingMaskIntoConstraints = false
            let xCenterConstraint = NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: activityIndicator, attribute: .centerX, multiplier: 1, constant: 0)
            let yCenterConstraint = NSLayoutConstraint(item: self, attribute: .centerY, relatedBy: .equal, toItem: activityIndicator, attribute: .centerY, multiplier: 1, constant: 0)
            self.addConstraints([xCenterConstraint, yCenterConstraint])
            return activityIndicator
        }()
    
        func showLoading() {
            activityIndicator.startAnimating()
            var buttonStates: [ButtonState] = []
            for state in [UIControlState.disabled] {
                let buttonState = ButtonState(state: state, title: title(for: state), image: image(for: state))
                buttonStates.append(buttonState)
                setTitle("", for: state)
                setImage(UIImage(), for: state)
            }
            self.buttonStates = buttonStates
            isEnabled = false
        }
    
        func hideLoading() {
            activityIndicator.stopAnimating()
            for buttonState in buttonStates {
                setTitle(buttonState.title, for: buttonState.state)
                setImage(buttonState.image, for: buttonState.state)
            }
            isEnabled = true
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题