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
Swift 5, Xcode 11.3
I've modified it for my use case to include the button text, together with the spinner
import UIKit
class LoadingButton: UIButton {
var activityIndicator: UIActivityIndicatorView!
let activityIndicatorColor: UIColor = .gray
func loadIndicator(_ shouldShow: Bool) {
if shouldShow {
if (activityIndicator == nil) {
activityIndicator = createActivityIndicator()
}
self.isEnabled = false
self.alpha = 0.7
showSpinning()
} else {
activityIndicator.stopAnimating()
self.isEnabled = true
self.alpha = 1.0
}
}
private func createActivityIndicator() -> UIActivityIndicatorView {
let activityIndicator = UIActivityIndicatorView()
activityIndicator.hidesWhenStopped = true
activityIndicator.color = activityIndicatorColor
return activityIndicator
}
private func showSpinning() {
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(activityIndicator)
positionActivityIndicatorInButton()
activityIndicator.startAnimating()
}
private func positionActivityIndicatorInButton() {
let trailingConstraint = NSLayoutConstraint(item: self,
attribute: .trailing,
relatedBy: .equal,
toItem: activityIndicator,
attribute: .trailing,
multiplier: 1, constant: 16)
self.addConstraint(trailingConstraint)
let yCenterConstraint = NSLayoutConstraint(item: self,
attribute: .centerY,
relatedBy: .equal,
toItem: activityIndicator,
attribute: .centerY,
multiplier: 1, constant: 0)
self.addConstraint(yCenterConstraint)
}
}
If you're using storyboard, ensure that your button is of type LoadingButton (do this on your storyboard as well as view controller file, otherwise it'll crash)
@IBOutlet weak var myButton: LoadingButton!
and to use it,
myButton.loadIndicator(true)
Another solution for Swift4, I tried to make it simpler than previous solutions. This Extension allows you to resize the UIActivityIndicatorView (scale) to make fit inside the UIButton, and change the color.
https://gist.github.com/jalopezsuarez/0ecc885b3fd5c555630799a067d66d98
import Foundation
import UIKit
class UIButtonActivity: UIButton {
@IBInspectable var indicatorColor : UIColor = .lightGray
private var buttonLabel: String?
func startAnimating() {
self.isEnabled = false
buttonLabel = self.titleLabel?.text
self.setTitle("", for: .normal)
let indicator = UIActivityIndicatorView()
indicator.color = indicatorColor
indicator.hidesWhenStopped = true
let buttonHeight = self.bounds.size.height
let buttonWidth = self.bounds.size.width
indicator.center = CGPoint(x: buttonWidth/2, y: buttonHeight/2)
let scale = max(min((self.frame.size.height - 4) / 21, 2.0), 0.0)
let transform: CGAffineTransform = CGAffineTransform(scaleX: scale, y: scale)
indicator.transform = transform
self.addSubview(indicator)
indicator.startAnimating()
}
func stopAnimating() {
self.isEnabled = true
if let titleLabel = buttonLabel {
self.setTitle(titleLabel, for: .normal)
}
if let indicator = self.viewWithTag(tag) as? UIActivityIndicatorView {
indicator.stopAnimating()
indicator.removeFromSuperview()
}
}
}
Swift 4:
extension UIButton {
func loadingIndicator(_ show: Bool) {
let tag = 808404
if show {
self.isEnabled = false
self.alpha = 0.5
let indicator = UIActivityIndicatorView()
let buttonHeight = self.bounds.size.height
let buttonWidth = self.bounds.size.width
indicator.center = CGPoint(x: buttonWidth/2, y: buttonHeight/2)
indicator.tag = tag
self.addSubview(indicator)
indicator.startAnimating()
} else {
self.isEnabled = true
self.alpha = 1.0
if let indicator = self.viewWithTag(tag) as? UIActivityIndicatorView {
indicator.stopAnimating()
indicator.removeFromSuperview()
}
}
}
}
Usage: button.loadingIndicator(true/false)
i have written a library in swift, it has 7 different styles and animations to show an indicatorview in uibutton, here it is
https://github.com/farshadjahanmanesh/loady