¿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?
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:
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
funcviewDidLoad() {
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
}
overridefuncviewDidLoad() {
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()
}
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:
Aquí está mi código de arrastrar y soltar:
var boxView = UIView()
overridefuncviewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
view.backgroundColor = UIColor.blackColor()
addSavingPhotoView()
//Custom button to test this appvar 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)
}
funcaddSavingPhotoView() {
// 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 initializedvar 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)
}
funcbuttonAction(sender:UIButton!) {
//When button is pressed it removes the boxView from screen
boxView.removeFromSuperview()
}
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
Uso
classLoginTVC: UITableViewController{
var loadingView : LoadingView!overridefuncviewDidLoad() {
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@IBActionfuncshowLoadingView(_ sender: UIButton) {
iflet loaderView = loadingView{ // If loadingView already existsif 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@IBActionfunchideLoadingView(_ sender: UIButton) {
iflet loaderView = loadingView{ // If loadingView already exists self.loadingView.hide()
}
}
}
LoadingView clase
classLoadingView{
let uiView : UIViewlet message : Stringlet 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()
}
funcsetup(){
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 dictionarylet 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 loadingViewfuncshow() {
loadingView.isHidden = false
}
// Call this method to show loadingViewfunchide(){
loadingView.isHidden = true
}
// Call this method to check if loading view already existsfuncisHidden() -> Bool{
if loadingView.isHidden == false{
returnfalse
}
else{
returntrue
}
}
}
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.
Respuestas:
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() } }
fuente
removeFromSuperview
y configuré anil
. ¡No estoy seguro de si es la mejor manera, pero su código establecido anteriormente ayudó mucho!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:
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.
fuente
label.color = <color>
se ignora: -Slabel.textColor = UIColor.greenColor()
, no afectará al color del texto.Así es como se ve este código:
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
fuente
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
UIViewController
clase: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() }
fuente
Para Swift 3
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 } } }
fuente
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
UIActivityIndicatorView
aUILabel
: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)
fuente
IBAction
en mi controlador de vista y no pasó nadaview
Debe 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 unUIVisualEffectView
para difuminar el fondo detrás de él.wait.hidesWhenStopped = false
. Pregunta: ¿cómo ocultar el objetoview
?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() }
fuente
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() }
fuente
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 :-
fuente
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(_:))
fuente
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 } }
fuente
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()
fuente
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 }
fuente
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() } } }
fuente