web-dev-qa-db-fra.com

Affichage de l’indicateur d’activité dans UIButton

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
17
clemkoa

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)
}
}
30
Steve Rosenberg

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

}
21
Kurt J

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

}
7
Carlos

j'ai écrit une bibliothèque dans Swift, il a 7 styles et animations différents pour montrer un indicateur en uibutton, le voici

https://github.com/farshadjahanmanesh/loady 

 enter image description here

1
Farshad jahanmanesh

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

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)
    }
}
0
Boris Nikolić

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
    }
}
0
infiniteLoop