在UIButton中显示活动指示器

我想在按下后将UIButton的内容更改为ActivityIndi​​cator。

我知道按钮有一个imageView和一个titleLabel,但我不知道如何在其中任何一个中放置一个活动指示器。

这就是我创建活动指标的方式:

let aiView = UIActivityIndicatorView(activityIndicatorStyle: .Gray) aiView.startAnimating() aiView.center = CGPointMake(0,0) aiView.hidesWhenStopped = false 

代码在这里找到:

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

 import UIKit class LoadingButton: UIButton { 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:这不应该在扩展名中。

这里是快速的3/4,改进的代码:禁用按钮,使用图像和标题。

 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稍作修改

 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) } } 

更新了Apple Swift 3.0.1版的选定答案(steve-rosenberg)(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) } } 

优秀@Steve,

可以使用以下实现代替行,

var activityIndi​​cator:UIActivityIndi​​catorView!

使用这个,这样如果我们在调用showLoading()之前配置活动指示器,应用程序就不会崩溃。

 private var _activityIndicator:UIActivityIndicatorView! = nil var activityIndicator: UIActivityIndicatorView{ set{ _activityIndicator = newValue } get{ if _activityIndicator == nil{ _activityIndicator = createActivityIndicator() } return _activityIndicator } } 

Swift4的另一个解决方案,我试图让它比以前的解决方案更简单。 此扩展允许您调整UIActivityIndi​​catorView(比例)的大小以使其适合UIButton,并更改颜色。

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() } } }