在UIButton中显示活动指示器

时间:2016-04-11 04:02:08

标签: ios swift uibutton

我希望在按下UIButton后将其更改为ActivityIndi​​cator。

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

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

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

10 个答案:

答案 0 :(得分:21)

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

}

答案 1 :(得分:9)

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

}

答案 2 :(得分:5)

Swift 5,Xcode 11.3

我已针对用例对其进行了修改,以包括按钮文本以及微调框

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

}

如果您正在使用情节提要,请确保您的按钮的类型为LoadingButton(在情节提要以及视图控制器文件上执行此操作,否则会崩溃)

@IBOutlet weak var myButton: LoadingButton!

并使用它,

myButton.loadIndicator(true)

Screenshot

答案 3 :(得分:1)

我用 swift 编写了一个库,它具有 7种不同的样式和动画以在uibutton中显示指标视图,在这里

https://github.com/farshadjahanmanesh/loady

enter image description here

答案 4 :(得分:1)

这是我的编辑,代码更少。

@Bean
public ReactiveRedisTemplate<String, String> reactiveRedisTemplateString
  (ReactiveRedisConnectionFactory connectionFactory) {
    return new ReactiveRedisTemplate<>(connectionFactory, RedisSerializationContext.string());
}

答案 5 :(得分:0)

更新了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)
    }
}

答案 6 :(得分:0)

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

答案 7 :(得分:0)

另一个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()
        }
    }
}

答案 8 :(得分:0)

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

} 然后button.loadingIndicator(true / false)

答案 9 :(得分:0)

大多数答案仅适用于标题,就我而言,我还需要管理属性文本和图像,

import UIKit

class LoadingButton: UIButton {

    struct ButtonState {
        var state: UIControl.State
        var title: String?
        var attributedTitle: NSAttributedString?
        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.color = self.titleColor(for: .normal)
        activityIndicator.startAnimating()
        var buttonStates: [ButtonState] = []
        for state in [UIControl.State.disabled] {
            let buttonState = ButtonState(state: state, title: title(for: state), attributedTitle: attributedTitle(for: state), image: image(for: state))
        buttonStates.append(buttonState)
            setTitle("", for: state)
            setAttributedTitle(NSAttributedString(string: ""), 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)
           setAttributedTitle(buttonState.attributedTitle, for: buttonState.state)
       }
       isEnabled = true
    }
}