Je voudrais changer le contenu d'un UIButton en un ActivityIndicator après avoir appuyé dessus.
Je sais que les boutons ont une imageView et un titleLabel, mais je ne sais pas comment mettre un indicateur d'activité dans aucun d'entre eux.
Voici comment je crée des indicateurs d'activité:
let aiView = UIActivityIndicatorView(activityIndicatorStyle: .Gray)
aiView.startAnimating()
aiView.center = CGPointMake(0,0)
aiView.hidesWhenStopped = false
Code trouvé ici:
http://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: Cela ne devrait pas être dans une extension.
Le voici dans Swift 3/4, avec le code amélioré: bouton de désactivation, fonctionne avec les images et les titres.
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 avec une petite 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)
}
}
j'ai écrit une bibliothèque dans Swift, il a 7 styles et animations différents pour montrer un indicateur en uibutton, le voici
Une autre solution pour Swift4, j'ai essayé de la simplifier par rapport aux solutions précédentes. Cette extension vous permet de redimensionner UIActivityIndicatorView (scale) pour s’adapter à l’intérieur du bouton UIB et de modifier la couleur.
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()
}
}
}
Réponse sélectionnée mise à jour (steve-rosenberg) pour 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)
}
}
Excellent @Steve,
Peut utiliser ci-dessous l'implémentation au lieu de la ligne,
var activityIndicator: UIActivityIndicatorView!
utilisez ceci, de sorte que si nous configurons l'indicateur d'activité avant d'appeler showLoading (), l'application ne plantera pas.
private var _activityIndicator:UIActivityIndicatorView! = nil
var activityIndicator: UIActivityIndicatorView{
set{
_activityIndicator = newValue
}
get{
if _activityIndicator == nil{
_activityIndicator = createActivityIndicator()
}
return _activityIndicator
}
}