¿Cómo mostrar un indicador de actividad con texto en iOS 8 con Swift?

81

Quiero mostrar, mediante programación, un indicador de actividad con texto, como el de la aplicación Fotos (después de editar y guardar una imagen). ¿Cómo puedo hacer esto?

ingrese la descripción de la imagen aquí

rodrigoalvesvieira
fuente
2
Aquí hay una versión de código abierto de esto que hice github.com/goktugyil/CozyLoadingActivity
Esqarrouth

Respuestas:

130

Xcode 9.0 • Swift 4.0


import UIKit
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var filterButton: UIButton!
    @IBOutlet weak var saveButton: UIButton!
    let destinationUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        .appendingPathComponent("filteredImage.png")
    let imagePicker = UIImagePickerController()
    let messageFrame = UIView()
    var activityIndicator = UIActivityIndicatorView()
    var strLabel = UILabel()
    let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
    func activityIndicator(_ title: String) {
        strLabel.removeFromSuperview()
        activityIndicator.removeFromSuperview()
        effectView.removeFromSuperview()
        strLabel = UILabel(frame: CGRect(x: 50, y: 0, width: 160, height: 46))
        strLabel.text = title
        strLabel.font = .systemFont(ofSize: 14, weight: .medium)
        strLabel.textColor = UIColor(white: 0.9, alpha: 0.7)
        effectView.frame = CGRect(x: view.frame.midX - strLabel.frame.width/2, y: view.frame.midY - strLabel.frame.height/2 , width: 160, height: 46)
        effectView.layer.cornerRadius = 15
        effectView.layer.masksToBounds = true
        activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .white)
        activityIndicator.frame = CGRect(x: 0, y: 0, width: 46, height: 46)
        activityIndicator.startAnimating()
        effectView.contentView.addSubview(activityIndicator)
        effectView.contentView.addSubview(strLabel)
        view.addSubview(effectView)
    }
    func saveImage() {
        do {
            try imageView.image?.data?.write(to: destinationUrl, options: .atomic)
            print("file saved")
        } catch {
            print(error)
        }
    }        
    func applyFilterToImage() {
        imageView.image = imageView.image?.applying(contrast: 1.5)
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        guard let url = URL(string: "https://upload.wikimedia.org/wikipedia/commons/a/a8/VST_images_the_Lagoon_Nebula.jpg"), let data = try? Data(contentsOf: url), let image = UIImage(data: data) else { return }
        view.backgroundColor = UIColor(white: 0, alpha: 1)
        imageView.image = image
    }
    @IBAction func startSavingImage(_ sender: AnyObject) {
        saveButton.isEnabled = false
        filterButton.isEnabled = false
        activityIndicator("Saving Image")
        DispatchQueue.main.async {
            self.saveImage()
            DispatchQueue.main.async {
                self.effectView.removeFromSuperview()
                self.saveButton.isEnabled = true
                self.filterButton.isEnabled = true
            }
        }
    }
    @IBAction func filterAction(_ sender: AnyObject) {
        filterButton.isEnabled = false
        saveButton.isEnabled = false
        activityIndicator("Applying Filter")
        DispatchQueue.main.async {
            self.applyFilterToImage()
            DispatchQueue.main.async {
                self.effectView.removeFromSuperview()
                self.filterButton.isEnabled = true
                self.saveButton.isEnabled = true
            }
        }
    }
    @IBAction func cameraAction(_ sender: AnyObject) {
        if UIImagePickerController.isSourceTypeAvailable(.camera) {
            imagePicker.delegate = self
            imagePicker.sourceType = .camera
            present(imagePicker, animated: true)
        }
    }
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [AnyHashable: Any]!) {
        dismiss(animated: true, completion: nil)
        imageView.image = image
    }
}

extension Data {
    var image: UIImage? { return UIImage(data: self) }
}

extension UIImage {
    var data: Data? { return UIImagePNGRepresentation(self) }
    func applying(contrast value: NSNumber) -> UIImage? {
        guard let ciImage = CIImage(image: self)?.applyingFilter("CIColorControls", withInputParameters: [kCIInputContrastKey: value]) else { return nil }
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        defer { UIGraphicsEndImageContext() }
        UIImage(ciImage: ciImage).draw(in: CGRect(origin: .zero, size: size))
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}

Leo Dabus
fuente
Modifiqué progressBarDisplayer para que fuera una clase y lo mostrara pasando la vista como parámetro. ¿Cómo identificarías el progressBarDisplayer que ya se ha agregado y lo eliminarías cuando todo haya terminado de cargarse?
simplexity
1
@simplexity no dude en abrir una nueva pregunta, publicar su código real allí y avíseme si desea que le eche un vistazo.
Leo Dabus
¡Gracias por su respuesta! De hecho, terminé almacenando la vista creada en una variable y haciendo referencia a ella removeFromSuperviewy configuré a nil. ¡No estoy seguro de si es la mejor manera, pero su código establecido anteriormente ayudó mucho!
simplexity
algo para Objective-C?
Artem Zaytsev
@KrishnaMeena ¿Qué no está funcionando? ¿Cuál es el error que está recibiendo en qué línea?
Leo Dabus
117

Si bien la respuesta de Esq funciona, agregué mi propia implementación, que está más en línea con una buena arquitectura de componentes al separar la vista en su propia clase. También utiliza el desenfoque dinámico introducido en iOS 8.

Así es como se ve el mío con un fondo de imagen:

ingrese la descripción de la imagen aquí

El código para esto está encapsulado en su propia clase UIView, lo que significa que puede reutilizarlo cuando lo desee.

Actualizado para Swift 3

Uso

func viewDidLoad() {
  super.viewDidLoad()

  // Create and add the view to the screen.
  let progressHUD = ProgressHUD(text: "Saving Photo")
  self.view.addSubview(progressHUD)
  // All done!

  self.view.backgroundColor = UIColor.black
}

Código UIView

import UIKit

class ProgressHUD: UIVisualEffectView {

  var text: String? {
    didSet {
      label.text = text
    }
  }

  let activityIndictor: UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
  let label: UILabel = UILabel()
  let blurEffect = UIBlurEffect(style: .light)
  let vibrancyView: UIVisualEffectView

  init(text: String) {
    self.text = text
    self.vibrancyView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: blurEffect))
    super.init(effect: blurEffect)
    self.setup()
  }

  required init?(coder aDecoder: NSCoder) {
    self.text = ""
    self.vibrancyView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: blurEffect))
    super.init(coder: aDecoder)
    self.setup()
  }

  func setup() {
    contentView.addSubview(vibrancyView)
    contentView.addSubview(activityIndictor)
    contentView.addSubview(label)
    activityIndictor.startAnimating()
  }

  override func didMoveToSuperview() {
    super.didMoveToSuperview()

    if let superview = self.superview {

      let width = superview.frame.size.width / 2.3
      let height: CGFloat = 50.0
      self.frame = CGRect(x: superview.frame.size.width / 2 - width / 2,
                      y: superview.frame.height / 2 - height / 2,
                      width: width,
                      height: height)
      vibrancyView.frame = self.bounds

      let activityIndicatorSize: CGFloat = 40
      activityIndictor.frame = CGRect(x: 5,
                                      y: height / 2 - activityIndicatorSize / 2,
                                      width: activityIndicatorSize,
                                      height: activityIndicatorSize)

      layer.cornerRadius = 8.0
      layer.masksToBounds = true
      label.text = text
      label.textAlignment = NSTextAlignment.center
      label.frame = CGRect(x: activityIndicatorSize + 5,
                           y: 0,
                           width: width - activityIndicatorSize - 15,
                           height: height)
      label.textColor = UIColor.gray
      label.font = UIFont.boldSystemFont(ofSize: 16)
    }
  }

  func show() {
    self.isHidden = false
  }

  func hide() {
    self.isHidden = true
  }
}

Swift 2

Un ejemplo de cómo usarlo es así:

override func viewDidLoad() {
    super.viewDidLoad()

    // Create and add the view to the screen.
    let progressHUD = ProgressHUD(text: "Saving Photo")
    self.view.addSubview(progressHUD)
    // All done!

    self.view.backgroundColor = UIColor.blackColor()
}

Aquí está el código de UIView:

import UIKit

class ProgressHUD: UIVisualEffectView {

    var text: String? {
        didSet {
            label.text = text
        }
    }
    let activityIndictor: UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.White)
    let label: UILabel = UILabel()
    let blurEffect = UIBlurEffect(style: .Light)
    let vibrancyView: UIVisualEffectView

    init(text: String) {
        self.text = text
        self.vibrancyView = UIVisualEffectView(effect: UIVibrancyEffect(forBlurEffect: blurEffect))
        super.init(effect: blurEffect)
        self.setup()
    }

    required init(coder aDecoder: NSCoder) {
        self.text = ""
        self.vibrancyView = UIVisualEffectView(effect: UIVibrancyEffect(forBlurEffect: blurEffect))
        super.init(coder: aDecoder)
        self.setup()

    }

    func setup() {
        contentView.addSubview(vibrancyView)
        vibrancyView.contentView.addSubview(activityIndictor)
        vibrancyView.contentView.addSubview(label)
        activityIndictor.startAnimating()
    }

    override func didMoveToSuperview() {
        super.didMoveToSuperview()

        if let superview = self.superview {

            let width = superview.frame.size.width / 2.3
            let height: CGFloat = 50.0
            self.frame = CGRectMake(superview.frame.size.width / 2 - width / 2,
                superview.frame.height / 2 - height / 2,
                width,
                height)
            vibrancyView.frame = self.bounds

            let activityIndicatorSize: CGFloat = 40
            activityIndictor.frame = CGRectMake(5, height / 2 - activityIndicatorSize / 2,
                activityIndicatorSize,
                activityIndicatorSize)

            layer.cornerRadius = 8.0
            layer.masksToBounds = true
            label.text = text
            label.textAlignment = NSTextAlignment.Center
            label.frame = CGRectMake(activityIndicatorSize + 5, 0, width - activityIndicatorSize - 15, height)
            label.textColor = UIColor.grayColor()
            label.font = UIFont.boldSystemFontOfSize(16)
        }
    }

    func show() {
        self.hidden = false
    }

    func hide() {
        self.hidden = true
    }
}

Espero que esto ayude, no dude en usar este código donde lo necesite.

Elliott Minns
fuente
Hola, Gracias por el código, pero sigo encontrando errores, declarando un viewDidLoad como se sugiere y obtiene el siguiente error: 0x2dd698 de la clase '_TtC22LabMaternalhaematology11ProgressHUD' no implementa doesNotRecognizeSelector: - abortar (lldb). Necesito poder mostrar y ocultar dentro de los cierres, así que necesito hacer una referencia para objetar una referencia de instancia
dancingbush
@dancingbush, ¿alguna vez te diste cuenta de esto? Recibo el mismo error ahora, por alguna razón, no cambió nada, el error acaba de comenzar a ocurrir
Tyler
1
Este es definitivamente el mejor enfoque (una clase reutilizable), pero el texto de la etiqueta y la ruleta son demasiado claros para verlos correctamente. Y label.color = <color>se ignora: -S
Pylinux
1
@ElliottMinns eso es lo que quise decir (pseudo código de ig). Si lo hago label.textColor = UIColor.greenColor(), no afectará al color del texto.
Pylinux
2
@ElliottMinns Esto no aparece en el centro de la pantalla (probado en el simulador de iPhone 7 Plus)
Dee
19

Así es como se ve este código:

ingrese la descripción de la imagen aquí

Aquí está mi código de arrastrar y soltar:

var boxView = UIView()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    view.backgroundColor = UIColor.blackColor()
    addSavingPhotoView()

    //Custom button to test this app
    var button = UIButton(frame: CGRect(x: 20, y: 20, width: 20, height: 20))
    button.backgroundColor = UIColor.redColor()
    button.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)

    view.addSubview(button)
}

func addSavingPhotoView() {
    // You only need to adjust this frame to move it anywhere you want
    boxView = UIView(frame: CGRect(x: view.frame.midX - 90, y: view.frame.midY - 25, width: 180, height: 50))
    boxView.backgroundColor = UIColor.whiteColor()
    boxView.alpha = 0.8
    boxView.layer.cornerRadius = 10

    //Here the spinnier is initialized
    var activityView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
    activityView.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
    activityView.startAnimating()

    var textLabel = UILabel(frame: CGRect(x: 60, y: 0, width: 200, height: 50))
    textLabel.textColor = UIColor.grayColor()
    textLabel.text = "Saving Photo"

    boxView.addSubview(activityView)
    boxView.addSubview(textLabel)

    view.addSubview(boxView)
}

func buttonAction(sender:UIButton!) {
    //When button is pressed it removes the boxView from screen
    boxView.removeFromSuperview()
}

Aquí hay una versión de código abierto de esto: https://github.com/goktugyil/CozyLoadingActivity

Esqarrouth
fuente
2
Aquí hay una versión de código abierto de esto que hice github.com/goktugyil/CozyLoadingActivity
Esqarrouth
10

Basado en mi respuesta anterior, aquí hay una solución más elegante con una clase personalizada:

Primero defina esta clase personalizada:

import UIKit
import Foundation

class ActivityIndicatorView
{
    var view: UIView!

var activityIndicator: UIActivityIndicatorView!

var title: String!

init(title: String, center: CGPoint, width: CGFloat = 200.0, height: CGFloat = 50.0)
{
    self.title = title

    let x = center.x - width/2.0
    let y = center.y - height/2.0

    self.view = UIView(frame: CGRect(x: x, y: y, width: width, height: height))
    self.view.backgroundColor = UIColor(red: 255.0/255.0, green: 204.0/255.0, blue: 51.0/255.0, alpha: 0.5)
    self.view.layer.cornerRadius = 10

    self.activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
    self.activityIndicator.color = UIColor.blackColor()
    self.activityIndicator.hidesWhenStopped = false

    let titleLabel = UILabel(frame: CGRect(x: 60, y: 0, width: 200, height: 50))
    titleLabel.text = title
    titleLabel.textColor = UIColor.blackColor()

    self.view.addSubview(self.activityIndicator)
    self.view.addSubview(titleLabel)
}

func getViewActivityIndicator() -> UIView
{
    return self.view
}

func startAnimating()
{
    self.activityIndicator.startAnimating()
    UIApplication.sharedApplication().beginIgnoringInteractionEvents()
}

func stopAnimating()
{
    self.activityIndicator.stopAnimating()
    UIApplication.sharedApplication().endIgnoringInteractionEvents()

    self.view.removeFromSuperview()
}
//end
}

Ahora en tu UIViewControllerclase:

var activityIndicatorView: ActivityIndicatorView!

override func viewDidLoad()
{
    super.viewDidLoad()

    self.activityIndicatorView = ActivityIndicatorView(title: "Processing...", center: self.view.center)
    self.view.addSubview(self.activityIndicatorView.getViewActivityIndicator())

}

func doSomething()
{
    self.activityIndicatorView.startAnimating()
    UIApplication.sharedApplication().beginIgnoringInteractionEvents()

    //do something here that will taking time

    self.activityIndicatorView.stopAnimating()
}
Thiago Arreguy
fuente
Pregunta rápida. ¿Por qué llamas a UIApplication.sharedApplication (). BeginIgnoringInteractionEvents () dos veces en doSomething () -> self.activityIndicatorView.startAnimating () luego de esa llamada?
Jason Foglia
6

Para Swift 3

ingrese la descripción de la imagen aquí

Uso

class LoginTVC: UITableViewController {
    var loadingView : LoadingView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // CASE 1: To Show loadingView on load

        loadingView = LoadingView(uiView: view, message: "Sending you verification code")
    }

    // CASE 2: To show loadingView on click of a button

    @IBAction func showLoadingView(_ sender: UIButton) {
        if let loaderView = loadingView{ // If loadingView already exists
            if loaderView.isHidden() {
                loaderView.show()  // To show activity indicator
            }
        }
        else{
            loadingView = LoadingView(uiView: view, message: "Sending you verification code")
         }
    }
}

    // CASE 3: To hide LoadingView on click of a button

    @IBAction func hideLoadingView(_ sender: UIButton) {
        if let loaderView = loadingView{ // If loadingView already exists 
            self.loadingView.hide()   
        }
    }
}

LoadingView clase

class LoadingView {

    let uiView          :   UIView
    let message         :   String
    let messageLabel    =   UILabel()

    let loadingSV       =   UIStackView()
    let loadingView     =   UIView()
    let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)

    init(uiView: UIView, message: String) {
        self.uiView     =   uiView
        self.message    =   message
        self.setup()
    }

    func setup(){
        let viewWidth   = uiView.bounds.width
        let viewHeight  = uiView.bounds.height

        // Configuring the message label
        messageLabel.text             = message
        messageLabel.textColor        = UIColor.darkGray
        messageLabel.textAlignment    = .center
        messageLabel.numberOfLines    = 3
        messageLabel.lineBreakMode    = .byWordWrapping

        // Creating stackView to center and align Label and Activity Indicator
        loadingSV.axis          = .vertical
        loadingSV.distribution  = .equalSpacing
        loadingSV.alignment     = .center
        loadingSV.addArrangedSubview(activityIndicator)
        loadingSV.addArrangedSubview(messageLabel)

        // Creating loadingView, this acts as a background for label and activityIndicator
        loadingView.frame           = uiView.frame
        loadingView.center          = uiView.center
        loadingView.backgroundColor = UIColor.darkGray.withAlphaComponent(0.3)
        loadingView.clipsToBounds   = true

        // Disabling auto constraints
        loadingSV.translatesAutoresizingMaskIntoConstraints = false

        // Adding subviews
        loadingView.addSubview(loadingSV)
        uiView.addSubview(loadingView)
        activityIndicator.startAnimating()

        // Views dictionary
        let views = [
            "loadingSV": loadingSV
        ]

        // Constraints for loadingSV
        uiView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[loadingSV(300)]-|", options: [], metrics: nil, views: views))
        uiView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-\(viewHeight / 3)-[loadingSV(50)]-|", options: [], metrics: nil, views: views))
    }

    // Call this method to hide loadingView
    func show() {
        loadingView.isHidden = false
    }

    // Call this method to show loadingView
    func hide(){
        loadingView.isHidden = true
    }

    // Call this method to check if loading view already exists
    func isHidden() -> Bool{
        if loadingView.isHidden == false{
            return false
        }
        else{
            return true
        }
    }
}
user44776
fuente
5

Puedes crear el tuyo propio. Por ejemplo:

Cree una vista con fondo blanco y esquinas redondeadas:

var view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 50))
view.backgroundColor = UIColor.whiteColor()
view.layer.cornerRadius = 10

Agregue dos subvistas, ay UIActivityIndicatorViewa UILabel:

var wait = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
wait.color = UIColor.blackColor()
wait.hidesWhenStopped = false


var text = UILabel(frame: CGRect(x: 60, y: 0, width: 200, height: 50))
text.text = "Processing..."

view.addSubview(wait)
view.addSubview(text)
MirekE
fuente
su código es fácil de entender pero no funciona. Tengo un botón en mi aplicación para guardar una imagen. Acabo de pegar este código IBActionen mi controlador de vista y no pasó nada
rodrigoalvesvieira
viewDebe agregar como una subvista de la vista donde está tratando de mostrar la ruleta. Además, parece que la versión de Apple puede estar usando un UIVisualEffectViewpara difuminar el fondo detrás de él.
Zev Eisenberg
Consulte el comentario de Zev. Mi código crea la vista, pero debe colocarla en algún lugar. Probablemente querrá hacer algo más agradable con las dimensiones.
MirekE
Ok, funciona aquí, pero cambio esto wait.hidesWhenStopped = false. Pregunta: ¿cómo ocultar el objeto view?
Thiago Arreguy
Respuesta: view.removeFromSuperview ()
Thiago Arreguy
5

Para el indicador de actividad, es mejor que cree una clase personalizada.

En lugar de crear UIActivityIndicator en cada UIViewController.Subclass UIView y usar desde cualquier UIViewController.

Actualizado para Swift 5.0:

import UIKit
import Foundation
class ProgressIndicator: UIView {

var indicatorColor:UIColor
var loadingViewColor:UIColor
var loadingMessage:String
var messageFrame = UIView()
var activityIndicator = UIActivityIndicatorView()

init(inview:UIView,loadingViewColor:UIColor,indicatorColor:UIColor,msg:String){

    self.indicatorColor = indicatorColor
    self.loadingViewColor = loadingViewColor
    self.loadingMessage = msg
    super.init(frame: CGRect(x: inview.frame.midX - 90, y: inview.frame.midY - 250 , width: 180, height: 50))
    initalizeCustomIndicator()

}
convenience init(inview:UIView) {

    self.init(inview: inview,loadingViewColor: UIColor.brown,indicatorColor:UIColor.black, msg: "Loading..")
}
convenience init(inview:UIView,messsage:String) {

    self.init(inview: inview,loadingViewColor: UIColor.brown,indicatorColor:UIColor.black, msg: messsage)
}

required init?(coder aDecoder: NSCoder) {

    fatalError("init(coder:) has not been implemented")
}

func initalizeCustomIndicator(){

    messageFrame.frame = self.bounds
    activityIndicator = UIActivityIndicatorView(style: UIActivityIndicatorView.Style.medium)
    activityIndicator.tintColor = indicatorColor
    activityIndicator.hidesWhenStopped = true
    activityIndicator.frame = CGRect(x: self.bounds.origin.x + 6, y: 0, width: 20, height: 50)
    print(activityIndicator.frame)
    let strLabel = UILabel(frame:CGRect(x: self.bounds.origin.x + 30, y: 0, width: self.bounds.width - (self.bounds.origin.x + 30) , height: 50))
    strLabel.text = loadingMessage
    strLabel.adjustsFontSizeToFitWidth = true
    strLabel.textColor = UIColor.white
    messageFrame.layer.cornerRadius = 15
    messageFrame.backgroundColor = loadingViewColor
    messageFrame.alpha = 0.8
    messageFrame.addSubview(activityIndicator)
    messageFrame.addSubview(strLabel)


}

func  start(){
    //check if view is already there or not..if again started
    if !self.subviews.contains(messageFrame){

        activityIndicator.startAnimating()
        self.addSubview(messageFrame)

    }
}

func stop(){

    if self.subviews.contains(messageFrame){

        activityIndicator.stopAnimating()
        messageFrame.removeFromSuperview()

    }
}
}

Coloque esta clase en su proyecto y luego llame desde cualquier ViewController como

var indicator:ProgressIndicator?
override func viewDidLoad() {
    super.viewDidLoad()

    //indicator = ProgressIndicator(inview: self.view,messsage: "Hello from Nepal..")
    //self.view.addSubview(indicator!)
    //OR
    indicator = ProgressIndicator(inview:self.view,loadingViewColor: UIColor.grayColor(), indicatorColor: UIColor.blackColor(), msg: "Landing within minutes,Please hold tight..")
    self.view.addSubview(indicator!)

}

@IBAction func startBtn(sender: AnyObject) {
    indicator!.start()
}


@IBAction func stopBtn(sender: AnyObject) {
    indicator!.stop()
}
Anish Parajuli 웃
fuente
4

Según la respuesta de "MirekE", aquí hay un código que probé ahora y está funcionando:

var activityIndicator: UIActivityIndicatorView!

var viewActivityIndicator: UIView!

override func viewDidLoad()
{
    super.viewDidLoad()

    let width: CGFloat = 200.0
    let height: CGFloat = 50.0
    let x = self.view.frame.width/2.0 - width/2.0
    let y = self.view.frame.height/2.0 - height/2.0

    self.viewActivityIndicator = UIView(frame: CGRect(x: x, y: y, width: width, height: height))
    self.viewActivityIndicator.backgroundColor = UIColor(red: 255.0/255.0, green: 204.0/255.0, blue: 51.0/255.0, alpha: 0.5)
    self.viewActivityIndicator.layer.cornerRadius = 10

    self.activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
    self.activityIndicator.color = UIColor.blackColor()
    self.activityIndicator.hidesWhenStopped = false

    let titleLabel = UILabel(frame: CGRect(x: 60, y: 0, width: 200, height: 50))
    titleLabel.text = "Processing..."

    self.viewActivityIndicator.addSubview(self.activityIndicator)
    self.viewActivityIndicator.addSubview(titleLabel)

    self.view.addSubview(self.viewActivityIndicator)
}

func doSometing()
{
    self.activityIndicator.startAnimating()
    UIApplication.sharedApplication().beginIgnoringInteractionEvents()

    //do something here that will taking time

    self.activityIndicator.stopAnimating()
    UIApplication.sharedApplication().endIgnoringInteractionEvents()
    self.viewActivityIndicator.removeFromSuperview()
}
Thiago Arreguy
fuente
2

clase de controlador de actividad simple !!!

class ActivityIndicator: UIVisualEffectView {


let activityIndictor: UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)
let label: UILabel = UILabel()
let blurEffect = UIBlurEffect(style: .Dark)
let vibrancyView: UIVisualEffectView

init() {

    self.vibrancyView = UIVisualEffectView(effect: UIVibrancyEffect(forBlurEffect: blurEffect))
    super.init(effect: blurEffect)
    self.setup()
}

required init?(coder aDecoder: NSCoder) {

    self.vibrancyView = UIVisualEffectView(effect: UIVibrancyEffect(forBlurEffect: blurEffect))
    super.init(coder: aDecoder)
    self.setup()
}

func setup() {

    contentView.addSubview(vibrancyView)
    vibrancyView.contentView.addSubview(activityIndictor)
    activityIndictor.startAnimating()
}

override func didMoveToSuperview() {
    super.didMoveToSuperview()

    if let superview = self.superview {
        let width: CGFloat = 75.0
        let height: CGFloat = 75.0
        self.frame = CGRectMake(superview.frame.size.width / 2 - width / 2,
                                superview.frame.height / 2 - height / 2,
                                width,
                                height)
        vibrancyView.frame = self.bounds
        let activityIndicatorSize: CGFloat = 40
        activityIndictor.frame = CGRectMake(18, height / 2 - activityIndicatorSize / 2,
                                            activityIndicatorSize,
                                            activityIndicatorSize)
        layer.cornerRadius = 8.0
        layer.masksToBounds = true

    }
}

func show() {
    self.hidden = false
}

func hide() {
    self.hidden = true
}}

uso: -

let activityIndicator = ActivityIndicator()
    self.view.addSubview(activityIndicator)

esconder :-

activityIndicator.hide()
Ashwin Felix
fuente
2

Xcode 10.1 • Swift 4.2

import UIKit

class ProgressHUD: UIVisualEffectView {

    var title: String?
    var theme: UIBlurEffect.Style = .light

    let strLabel = UILabel(frame: CGRect(x: 50, y: 0, width: 160, height: 46))
    let activityIndicator = UIActivityIndicatorView()

    init(title: String, theme: UIBlurEffect.Style = .light) {
        super.init(effect: UIBlurEffect(style: theme))

        self.title = title
        self.theme = theme

        [activityIndicator, strLabel].forEach(contentView.addSubview(_:))
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func didMoveToSuperview() {
        super.didMoveToSuperview()

        if let superview = self.superview {
            frame = CGRect(x: superview.frame.midX - strLabel.frame.width / 2,
                           y: superview.frame.midY - strLabel.frame.height / 2, width: 160, height: 46)

            layer.cornerRadius = 15.0
            layer.masksToBounds = true

            activityIndicator.frame = CGRect(x: 0, y: 0, width: 46, height: 46)
            activityIndicator.startAnimating()

            strLabel.text = title
            strLabel.font = .systemFont(ofSize: 14, weight: UIFont.Weight.medium)

            switch theme {
            case .dark:
                strLabel.textColor = .white
                activityIndicator.style = .white
            default:
                strLabel.textColor = .gray
                activityIndicator.style = .gray
            }
        }

    }

    func show() {
        self.isHidden = false
    }

    func hide() {
        self.isHidden = true
    }
}

Utilizar:

let progress = ProgressHUD(title: "Authorization", theme: .dark)
[progress].forEach(view.addSubview(_:))
Holofox
fuente
2

Con el ancho automático y la compatibilidad con el tema también detecta la rotación mientras está ocupado (versión Swift 3)

Úselo como a continuación:

var progressView: ProgressView?
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    self.progressView = ProgressView(message: "Work in progress!",
                                         theme: .dark,
                                         isModal: true)
}

@IBAction func onPause(_ sender: AnyObject) {
    self.progressView.show()      
}

@IBAction func onResume(_ sender: AnyObject) {
    self.progressView.hide()       
}

ProgressView.swift

import UIKit

class ProgressView: UIView {

    enum Theme {
        case light
        case dark
    }

    var theme: Theme
    var container: UIStackView
    var activityIndicator: UIActivityIndicatorView
    var label: UILabel
    var glass: UIView


    private var message: String
    private var isModal: Bool

    init(message: String, theme: theme, isModal: Bool) {
        // Init
        self.message = message
        self.theme = theme
        self.isModal = isModal

        self.container = UIStackView()
        self.activityIndicator = UIActivityIndicatorView()
        self.label = UILabel()
        self.glass = UIView()

        // Get proper width by text message
        let fontName = self.label.font.fontName
        let fontSize = self.label.font.pointSize
        if let font = UIFont(name: fontName, size: fontSize) {
            let fontAttributes = [NSFontAttributeName: font]
            let size = (message as NSString).size(attributes: fontAttributes)
            super.init(frame: CGRect(x: 0, y: 0, width: size.width + 50, height: 50))
        } else {
            super.init(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
        }

        // Detect rotation
        NotificationCenter.default.addObserver(self, selector: #selector(onRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)

        // Style
        self.layer.cornerRadius = 3
        if (self.theme == .dark) {
            self.backgroundColor = .darkGray
        } else {
            self.backgroundColor = .lightGray
        }

        // Label
        if self.theme == .dark {
            self.label.textColor = .white
        }else{
            self.label.textColor = .black
        }
        self.label.text = self.message
        // Container
        self.container.frame = self.frame
        self.container.spacing = 5
        self.container.layoutMargins = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
        self.container.isLayoutMarginsRelativeArrangement = true
        // Activity indicator
        if (self.theme == .dark) {
            self.activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
            self.activityIndicator.color = .white
        } else {
            self.activityIndicator = UIActivityIndicatorView(activityIndicatorStyle:.whiteLarge)
            self.activityIndicator.color = .black
        }
        self.activityIndicator.startAnimating()
        // Add them to container

        // First glass
        if let superview = UIApplication.shared.keyWindow {
            if (self.isModal) {
                // glass
                self.glass.frame = superview.frame;
                if (self.theme == .dark) {
                    self.glass.backgroundColor = UIColor.black.withAlphaComponent(0.5)
                } else {
                    self.glass.backgroundColor = UIColor.white.withAlphaComponent(0.5)
                }
                superview.addSubview(glass)
            }
        }
        // Then activity indicator and label
        container.addArrangedSubview(self.activityIndicator)
        container.addArrangedSubview(self.label)
        // Last attach it to container (StackView)
        self.addSubview(container)
        if let superview = UIApplication.shared.keyWindow {
            self.center = superview.center
            superview.addSubview(self)
        }
        //Do not show until show() is called
        self.hide()
    }

    required init(coder: NSCoder) {
        self.theme = .dark
        self.Message = "Not set!"
        self.isModal = true
        self.container = UIStackView()
        self.activityIndicator = UIActivityIndicatorView()
        self.label = UILabel()
        self.glass = UIView()
        super.init(coder: coder)!
    }

    func onRotate() {
        if let superview = self.superview {
            self.glass.frame = superview.frame
            self.center = superview.center
//            superview.addSubview(self)
        }
    }

    public func show() {
        self.glass.isHidden = false
        self.isHidden = false
    }

    public func hide() {
        self.glass.isHidden = true
        self.isHidden = true
    }
}
TheCoder
fuente
1

Este código funciona en SWIFT 2.0.

Debe declarar una variable para inicializar UIActivityIndicatorView

let actInd: UIActivityIndicatorView = UIActivityIndicatorView() 

Después de inicializar, ponga este código en su controlador.

actInd.center = ImageView.center
actInd.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.WhiteLarge
view.addSubview(actInd)
actInd.startAnimating()

después de que se complete el proceso de descarga, oculte una animación.

self.actInd.stopAnimating()
Himanshu Moradiya
fuente
1

En Swift 3

Declarar variables que usaremos

var activityIndicator = UIActivityIndicatorView()
let loadingView = UIView()
let loadingLabel = UILabel()

Establecer etiqueta, vista e indicador de actividad

func setLoadingScreen(myMsg : String) {
    let width: CGFloat = 120
    let height: CGFloat = 30
    let x = (self.view.frame.width / 2) - (width / 2)
    let y = (169 / 2) - (height / 2) + 60
    loadingView.frame = CGRect(x: x, y: y, width: width, height: height)
    self.loadingLabel.textColor = UIColor.white
    self.loadingLabel.textAlignment = NSTextAlignment.center
    self.loadingLabel.text = myMsg
    self.loadingLabel.frame = CGRect(x: 0, y: 0, width: 160, height: 30)
    self.loadingLabel.isHidden = false
    self.activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.white
    self.activityIndicator.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
    self.activityIndicator.startAnimating()
    loadingView.addSubview(self.spinner)
    loadingView.addSubview(self.loadingLabel)
    self.view.addSubview(loadingView)
}

Iniciar animación

@IBAction func start_animation(_ sender: Any) {
    setLoadingScreen(myMsg: "Loading...")
}

Detener animación

@IBAction func stop_animation(_ sender: Any) {
    self.spinner.stopAnimating()
    UIApplication.shared.endIgnoringInteractionEvents()
    self.loadingLabel.isHidden = true
}
Mili Shah
fuente
1
import UIKit

class ViewControllerUtils {

    let containerView: UIView = {

        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = UIColor(white: 0, alpha: 0.3)
        return view
    }()

    let loadingView: UIView = {

        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = UIColor(white: 0, alpha: 0.7)
        view.clipsToBounds = true
        view.layer.cornerRadius = 10
        return view
    }()

    let activityIndicatorView: UIActivityIndicatorView = {

        let aiv = UIActivityIndicatorView()
        aiv.translatesAutoresizingMaskIntoConstraints = false
        aiv.style = UIActivityIndicatorView.Style.whiteLarge
        return aiv
    }()

    let loadingLabel: UILabel = {

        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "Loading..."
        label.textAlignment = .center
        label.textColor = .white
        label.font = .systemFont(ofSize: 15, weight: UIFont.Weight.medium)
        return label
    }()

    func showLoader() {

        guard let window = UIApplication.shared.keyWindow else { return }

        window.addSubview(containerView)
        containerView.addSubview(loadingView)
        loadingView.addSubview(activityIndicatorView)
        loadingView.addSubview(loadingLabel)

        containerView.leftAnchor.constraint(equalTo: window.leftAnchor).isActive = true
        containerView.rightAnchor.constraint(equalTo: window.rightAnchor).isActive = true
        containerView.topAnchor.constraint(equalTo: window.topAnchor).isActive = true
        containerView.bottomAnchor.constraint(equalTo: window.bottomAnchor).isActive = true

        loadingView.centerXAnchor.constraint(equalTo: window.centerXAnchor).isActive = true
        loadingView.centerYAnchor.constraint(equalTo: window.centerYAnchor).isActive = true
        loadingView.widthAnchor.constraint(equalToConstant: 120).isActive = true
        loadingView.heightAnchor.constraint(equalToConstant: 120).isActive = true

        activityIndicatorView.centerXAnchor.constraint(equalTo: window.centerXAnchor).isActive = true
        activityIndicatorView.centerYAnchor.constraint(equalTo: window.centerYAnchor).isActive = true
        activityIndicatorView.widthAnchor.constraint(equalToConstant: 60).isActive = true
        activityIndicatorView.heightAnchor.constraint(equalToConstant: 60).isActive = true

        loadingLabel.leftAnchor.constraint(equalTo: loadingView.leftAnchor).isActive = true
        loadingLabel.rightAnchor.constraint(equalTo: loadingView.rightAnchor).isActive = true
        loadingLabel.bottomAnchor.constraint(equalTo: loadingView.bottomAnchor).isActive = true
        loadingLabel.heightAnchor.constraint(equalToConstant: 40).isActive = true

        DispatchQueue.main.async {

            self.activityIndicatorView.startAnimating()
        }
    }

    func hideLoader() {

        DispatchQueue.main.async {

            self.activityIndicatorView.stopAnimating()
            self.activityIndicatorView.removeFromSuperview()
            self.loadingLabel.removeFromSuperview()
            self.loadingView.removeFromSuperview()
            self.containerView.removeFromSuperview()
        }
    }
}

//// In order to show the activity indicator, call the function from your view controller
// let viewControllerUtils = ViewControllerUtils()
// viewControllerUtils.showLoader()

//// In order to hide the activity indicator, call the function from your view controller
// viewControllerUtils.hideLoader()

class ViewControllerUtils2 {

    var container: UIView = UIView()
    var loadingView: UIView = UIView()
    var activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView()
    let loadingLabel = UILabel()

    func showLoader(_ uiView: UIView) {

        container.frame = uiView.frame
        container.center = uiView.center
        container.backgroundColor = UIColor(white: 0, alpha: 0.3)

        loadingView.frame = CGRect(x: 0, y: 0, width: 120, height: 120)
        loadingView.center = uiView.center
        loadingView.backgroundColor = UIColor(white: 0, alpha: 0.7)
        loadingView.clipsToBounds = true
        loadingView.layer.cornerRadius = 10

        activityIndicator.frame = CGRect(x: 0, y: 0, width: 60, height: 60)
        activityIndicator.style = UIActivityIndicatorView.Style.whiteLarge
        activityIndicator.center = CGPoint(x: loadingView.frame.size.width / 2, y: loadingView.frame.size.height / 2)

        loadingLabel.frame = CGRect(x: 0, y: 80, width: 120, height: 40)
        loadingLabel.text = "Loading..."
        loadingLabel.textAlignment = .center
        loadingLabel.textColor = .white
        loadingLabel.font = .systemFont(ofSize: 15, weight: UIFont.Weight.medium)

        uiView.addSubview(container)
        container.addSubview(loadingView)
        loadingView.addSubview(activityIndicator)
        loadingView.addSubview(loadingLabel)

        DispatchQueue.main.async {

            self.activityIndicator.startAnimating()
        }
    }

    func hideLoader() {

        DispatchQueue.main.async {

            self.activityIndicator.stopAnimating()
            self.activityIndicator.removeFromSuperview()
            self.loadingLabel.removeFromSuperview()
            self.loadingView.removeFromSuperview()
            self.container.removeFromSuperview()
        }
    }
}
iAj
fuente
ViewControllerUtils se usa para todos los controladores de vista, donde, al igual que con webView, use ViewControllerUtils2 ..
iAj