Display activity indicator inside UIButton
import UIKitclass 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)}}
@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 }}
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) }}