How to show activity indicator while tableView loads? - ios

When I switch between my tabs it loads some seconds and I want to know that my data is loading. For that I decided to add an activity indicator.
I wrote a little function:
func showActivityIndicator() {
dispatch_async(dispatch_get_main_queue()) {
self.spinner = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge)
self.spinner.frame = CGRect(x: 0.0, y: 0.0, width: 80.0, height: 80.0)
self.spinner.center = CGPoint(x:self.loadingView.bounds.size.width / 2, y:self.loadingView.bounds.size.height / 2)
self.loadingView.addSubview(self.spinner)
self.view.addSubview(self.loadingView)
self.spinner.startAnimating()
}
}
that will show my indicator. And try to use it when I tapped from my infoController to button:
#IBAction func goToMainFromInfo(sender: AnyObject) {
self.showActivityIndicator()
self.performSegueWithIdentifier("fromMainToInfoWActivity", sender: nil)
self.hideActivityIndicator()
}
}
I show it before segue perform and hide after. It doesn't help me. When I did try to use sync:
#IBAction func goToMainFromInfo(sender: AnyObject) {
dispatch_async(dispatch_get_main_queue()) {
self.showActivityIndicator()
self.performSegueWithIdentifier("fromMainToInfoWActivity", sender: nil)
self.hideActivityIndicator()
}
}
But it doesn't help too. When I press to tab it opacity becomes 0.5 and I wait while it loading. But I do not see my activity indicator.
What is the problem?

Just try this:
var indicator = UIActivityIndicatorView()
func activityIndicator() {
indicator = UIActivityIndicatorView(frame: CGRectMake(0, 0, 40, 40))
indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
indicator.center = self.view.center
self.view.addSubview(indicator)
}
And where you want to start animating
indicator.startAnimating()
indicator.backgroundColor = UIColor.whiteColor()
For stop:
indicator.stopAnimating()
indicator.hidesWhenStopped = true
Note: Avoid the calling of start and stop at the same time. Just give some conditions.
SWIFT : 4.2
Just try this:
var indicator = UIActivityIndicatorView()
func activityIndicator() {
indicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
indicator.style = UIActivityIndicatorView.Style.gray
indicator.center = self.view.center
self.view.addSubview(indicator)
}
And where you want to start animating
activityIndicator()
indicator.startAnimating()
indicator.backgroundColor = .white
For stop:
indicator.stopAnimating()
indicator.hidesWhenStopped = true

Swift 3.0
// UIView Extension
fileprivate var ActivityIndicatorViewAssociativeKey = "ActivityIndicatorViewAssociativeKey"
public extension UIView {
var activityIndicatorView: UIActivityIndicatorView {
get {
if let activityIndicatorView = getAssociatedObject(&ActivityIndicatorViewAssociativeKey) as? UIActivityIndicatorView {
return activityIndicatorView
} else {
let activityIndicatorView = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
activityIndicatorView.activityIndicatorViewStyle = .gray
activityIndicatorView.color = .gray
activityIndicatorView.center = center
activityIndicatorView.hidesWhenStopped = true
addSubview(activityIndicatorView)
setAssociatedObject(activityIndicatorView, associativeKey: &ActivityIndicatorViewAssociativeKey, policy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return activityIndicatorView
}
}
set {
addSubview(newValue)
setAssociatedObject(newValue, associativeKey:&ActivityIndicatorViewAssociativeKey, policy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
// NSObject Extension
public extension NSObject {
func setAssociatedObject(_ value: AnyObject?, associativeKey: UnsafeRawPointer, policy: objc_AssociationPolicy) {
if let valueAsAnyObject = value {
objc_setAssociatedObject(self, associativeKey, valueAsAnyObject, policy)
}
}
func getAssociatedObject(_ associativeKey: UnsafeRawPointer) -> Any? {
guard let valueAsType = objc_getAssociatedObject(self, associativeKey) else {
return nil
}
return valueAsType
}
}
start animation
tableView.activityIndicatorView.startAnimating()
stop animation
tableView.activityIndicatorView.stopAnimating()
You can find more code in Magic

Swift 2+
class ViewController: UITableViewController {
weak var activityIndicatorView: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
let activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
tableView.backgroundView = activityIndicatorView
self.activityIndicatorView = activityIndicatorView
activityIndicatorView.startAnimating()
}
...
}

I use two extension methods to add an UIActivityIndicatorView as the backgroundView of the tableview.
extension UITableView {
func showActivityIndicator() {
DispatchQueue.main.async {
let activityView = UIActivityIndicatorView(style: .medium)
self.backgroundView = activityView
activityView.startAnimating()
}
}
func hideActivityIndicator() {
DispatchQueue.main.async {
self.backgroundView = nil
}
}
}
You can show/hide it like this.
tableView.showActivityIndicator()
tableView.hideActivityIndicator()

This code can help you :)
let indicator:UIActivityIndicatorView = UIActivityIndicatorView (activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
indicator.color = UIColor .magentaColor()
indicator.frame = CGRectMake(0.0, 0.0, 10.0, 10.0)
indicator.center = self.view.center
self.view.addSubview(indicator)
indicator.bringSubviewToFront(self.view)
indicator.startAnimating()

SWIFT
Place this below your class:
let indicator:UIActivityIndicatorView = UIActivityIndicatorView (activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
Place this in your loadView():
indicator.color = UIColor .magentaColor()
indicator.frame = CGRectMake(0.0, 0.0, 10.0, 10.0)
indicator.center = self.view.center
self.view.addSubview(indicator)
indicator.bringSubviewToFront(self.view)
indicator.startAnimating()
In my case, I am requesting json objects through a func request, so I placed this at the end of that function to remove the activity indicator once the data loads:
self.indicator.stopAnimating()
self.indicator.hidesWhenStopped = true

Another approach, In my code I added an extension for UITableView (Swift 2.3) :
extension UITableView {
func activityIndicator(center: CGPoint = CGPointZero, loadingInProgress: Bool) {
let tag = 12093
if loadingInProgress {
var indicator = UIActivityIndicatorView()
indicator = UIActivityIndicatorView(frame: CGRectMake(0, 0, 40, 40))
indicator.tag = tag
indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.WhiteLarge
indicator.color = //Your color here
indicator.center = center
indicator.startAnimating()
indicator.hidesWhenStopped = true
self.superview?.addSubview(indicator)
}else {
if let indicator = self.superview?.viewWithTag(tag) as? UIActivityIndicatorView { {
indicator.stopAnimating()
indicator.removeFromSuperview()
}
}
}
}
Note : My tableview is embedded in a UIView (superview)

Update Swift 4.2:
1.call the activityIndicator function on viewDidLoad
eg:
var indicator = UIActivityIndicatorView()
override func viewDidLoad() {
//Initializing the Activity Indicator
activityIndicator()
//Starting the Activity Indicator
indicator.startAnimating()
//Call Your WebService or API
callAPI()
}
Here is the Code For Adding ActivityIndicator as Subview
func activityIndicator() {
indicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
indicator.style = UIActivityIndicatorView.Style.whiteLarge
indicator.color = .red
indicator.center = self.view.center
self.view.addSubview(indicator)
}
2. Do UI related Operations or API Call and stop activity indicator
func callAPI() {
YourModelClass.fetchResult(someParams,
completionHandler: { (response) in
//Do necessary UIUpdates
//And stop Activity Indicator
self.indicator.stopAnimating()
})
}

func setupSpinner(){
spinner = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 40, height:40))
spinner.color = UIColor(Colors.Accent)
self.spinner.center = CGPoint(x:UIScreen.main.bounds.size.width / 2, y:UIScreen.main.bounds.size.height / 2)
self.view.addSubview(spinner)
spinner.hidesWhenStopped = true
}

Using "lazy var". It's better than function
fileprivate lazy var activityIndicatorView: UIActivityIndicatorView = {
let activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: .gray)
activityIndicatorView.hidesWhenStopped = true
// Set Center
var center = self.view.center
if let navigationBarFrame = self.navigationController?.navigationBar.frame {
center.y -= (navigationBarFrame.origin.y + navigationBarFrame.size.height)
}
activityIndicatorView.center = center
self.view.addSubview(activityIndicatorView)
return activityIndicatorView
}()
Just start the spinner anywhere
like this
func requestData() {
// Request something
activityIndicatorView.startAnimating()
}

#brocolli's answer for swift 4.0. You have to use objc_ before getting or setting associated objects. According to the documentation, The APIs of getting and setting the associated object in Swift are:
func objc_getAssociatedObject(object: AnyObject!,
key: UnsafePointer<Void>
) -> AnyObject!
func objc_setAssociatedObject(object: AnyObject!,
key: UnsafePointer<Void>,
value: AnyObject!,
policy: objc_AssociationPolicy)
Implementation:
import UIKit
fileprivate var ActivityIndicatorViewAssociativeKey = "ActivityIndicatorViewAssociativeKey"
extension UIView {
var activityIndicatorView: UIActivityIndicatorView {
get {
if let activityIndicatorView = objc_getAssociatedObject(self, &ActivityIndicatorViewAssociativeKey) as? UIActivityIndicatorView {
return activityIndicatorView
} else {
let activityIndicatorView = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
activityIndicatorView.activityIndicatorViewStyle = .gray
activityIndicatorView.color = .gray
activityIndicatorView.center = center
activityIndicatorView.hidesWhenStopped = true
addSubview(activityIndicatorView)
objc_setAssociatedObject(self, &ActivityIndicatorViewAssociativeKey, activityIndicatorView, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return activityIndicatorView
}
}
set {
addSubview(newValue)
objc_setAssociatedObject(self, &ActivityIndicatorViewAssociativeKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}

In order to place the UIActivityIndicator in foreground, even over the eventual UITableViewController separators, I have adopted this solution.
I have add the UIActivityIndicator programmatically, and add it as a subview of my UINavigationController
var activityIndicator: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
// Code
// .... omissis
// Set activity indicator
activityIndicator = UIActivityIndicatorView(style: .whiteLarge)
activityIndicator.color = UIColor.darkGray
activityIndicator.center = tableView.center
activityIndicator.hidesWhenStopped = true
activityIndicator.stopAnimating()
self.navigationController?.view.addSubview(activityIndicator)
}
I have just start & stop it when needed (in my case):
func animateActivityIndicator(_ sender: Any ) {
guard let vc = sender as? UIViewController else { return }
if let v = vc as? MyTableViewController {
if v.activityIndicator.isAnimating {
v.activityIndicator.stopAnimating()
} else {
v.activityIndicator.startAnimating()
}
}
// Others UIViewController or UITableViewController follows...
// all of them exhibits an activityIndicator variable
// implemented programmatically or with the storyboard
}
PS. My environment is Xcode 10.0, iOS 12.0

Related

How to isolate the loader screen code in swift?

I have created this custom code to create a loader in my project. The problem is that I have to copy and paste this function in all my classes. Is there any way I can declare this code in one global functions class and just use them wherever I want to use by calling.
import NVActivityIndicatorView
let activityIndicatorView = NVActivityIndicatorView(frame: CGRect(x: 80, y: 80, width: 60, height:60), type: .ballTrianglePath, color: .black)
let blurView = UIView()
func startLoader(){
DispatchQueue.main.async
{
self.blurView.isHidden = false
self.blurView.frame = self.view.frame
self.blurView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
self.view.addSubview(self.blurView)
self.activityIndicatorView.center = self.blurView.center
self.view.addSubview(self.activityIndicatorView)
self.activityIndicatorView.startAnimating()
}
}
func stopLoader(){
DispatchQueue.main.async {
self.activityIndicatorView.stopAnimating()
self.blurView.isHidden = true
}
}
First Create function to get activityIndicatorView and blurView. Because you don't need to repeat code in everywhere.And easily change entire loader views in one place
Class Helper {
static func getLoaderViews()->(UIView,NVActivityIndicatorView){
let activityIndicatorView = NVActivityIndicatorView(frame: CGRect(x: 80, y: 80, width: 60, height:60), type: .ballTrianglePath, color: .black)
let blurView = UIView()
// create your components,customise and return
return (blurView,activityIndicatorView)
}
}
now create a UIViewController Extension to start or stop loader
extension UIViewController {
func addLoaderToView(view:UIView,blurView:UIView ,activityIndicatorView:NVActivityIndicatorView) {
blurView.isHidden = false
blurView.frame = view.frame
blurView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
view.addSubview(blurView)
activityIndicatorView.center = blurView.center
view.addSubview(activityIndicatorView)
activityIndicatorView.startAnimating()
}
func removeLoader(activityIndicatorView:NVActivityIndicatorView,blurView:UIView) {
activityIndicatorView.stopAnimating()
blurView.isHidden = true
}
}
Now you can easily add or remove loader in any UIViewController
let (blurView,activityIndicatorView) = Helper.getLoaderViews() //In your class scope
//where you want to start
addLoaderToView(view:self.view,blurView:blurView ,activityIndicatorView:activityIndicatorView)
//where you want to stop
removeLoader(activityIndicatorView:activityIndicatorView,blurView:blurView)
You can create UIView extension
extension UIView {
func showActivity() {
let activityIndicatorView = NVActivityIndicatorView(frame: CGRect(x: 80, y: 80, width: 60, height:60), type: .ballTrianglePath, color: .black)
let blurView = UIView()
DispatchQueue.main.async {
self.blurView.isHidden = false
self.blurView.frame = self.frame
self.blurView.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
self.addSubview(self.blurView)
self.activityIndicatorView.center = self.blurView.center
self.addSubview(self.activityIndicatorView)
self.activityIndicatorView.startAnimating()
}
}
}

Animate thru various images in Swift - Using customized Load View

I have a customLoader which I would like to call anytime a user logs in. I want to animate thru all seven photos in gifArray.
import UIKit
class CustomLoader: UIView {
static let instance = CustomLoader()
let gifArray: [UIImage] = [UIImage(named: "beer1")!,UIImage(named: "beer2")!,UIImage(named: "beer3")!,UIImage(named: "beer4")!,UIImage(named: "beer5")!,UIImage(named: "beer6")!,UIImage(named: "beer7")!]
lazy var transparentView:UIView = {
let transparentView = UIView(frame: UIScreen.main.bounds)
transparentView.backgroundColor = UIColor.black.withAlphaComponent(0.7)
transparentView.isUserInteractionEnabled = false
return transparentView
} ()
lazy var gifImage: UIImageView = {
var gifImage = UIImageView(frame: CGRect(x: 0, y: 0, width: 200.00, height: 100))
gifImage.contentMode = .scaleAspectFit
gifImage.center = transparentView.center
gifImage.isUserInteractionEnabled = false
return gifImage
} ()
func animate() {
for image in gifArray {
gifImage.image = image
gifImage.animationRepeatCount = 1
gifImage.startAnimating()
}
}
func showLoader() {
self.addSubview(transparentView)
self.transparentView.addSubview(gifImage)
self.transparentView.bringSubviewToFront(self.gifImage)
animate()
}
func hideLoader() {
self.transparentView.removeFromSuperview()
}
}
I call it when the user logs in
In ViewDidLoad:
CustomLoader.instance.showLoader()
view.addSubview(CustomLoader.instance.transparentView)
view.bringSubviewToFront(CustomLoader.instance.transparentView)
Problem: It unfortunately just shows the last image. How do i fix this?
The for loop here sets the last image
for image in gifArray {
instead you need
gifImage.isUserInteractionEnabled = false
gifImage.animationImages = gifArray
Then
func animate() {
gifImage.startAnimating()
}

Swift: starting and stopping the animation of an activity indicator inside a custom class

I want to put an activity indicator inside a custom class so I can start/stop it from any view controller.
The below code works when starting the activity indicator but not stopping, how can I do this?
static func activityIndicatorFunction(view: UIView, targetVC: UIViewController, animate: Bool) {
var activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView()
if animate == false {
activityIndicator.stopAnimating()
UIApplication.shared.endIgnoringInteractionEvents()
} else {
activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
activityIndicator.backgroundColor = UIColor(red:0.16, green:0.17, blue:0.21, alpha:1)
activityIndicator.layer.cornerRadius = 6
activityIndicator.center = targetVC.view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.whiteLarge
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
//UIApplication.shared.beginIgnoringInteractionEvents()
}
}
An example of starting the activity indicator, the animate parameter would be false if I wanted to stop it.
Utils.activityIndicatorFunction(view: view, targetVC: self, animate: true)
This is a perfect candidate for protocol extensions. I recently did this myself.
First create the protocol in a file, say ActivityIndicatorPresenter.swift
/// Used for ViewControllers that need to present an activity indicator when loading data.
public protocol ActivityIndicatorPresenter {
/// The activity indicator
var activityIndicator: UIActivityIndicatorView { get }
/// Show the activity indicator in the view
func showActivityIndicator()
/// Hide the activity indicator in the view
func hideActivityIndicator()
}
Create a protocol extension (in the same file...or a different one)
public extension ActivityIndicatorPresenter where Self: UIViewController {
func showActivityIndicator() {
DispatchQueue.main.async {
self.activityIndicator.activityIndicatorViewStyle = .whiteLarge
self.activityIndicator.frame = CGRect(x: 0, y: 0, width: 80, height: 80) //or whatever size you would like
self.activityIndicator.center = CGPoint(x: self.view.bounds.size.width / 2, y: self.view.bounds.height / 2)
self.view.addSubview(self.activityIndicator)
self.activityIndicator.startAnimating()
}
}
func hideActivityIndicator() {
DispatchQueue.main.async {
self.activityIndicator.stopAnimating()
self.activityIndicator.removeFromSuperview()
}
}
}
Any view controller can then conform to the protocol
class MyViewController: UIViewController, ActivityIndicatorPresenter {
/// Make sure to add the activity indicator
var activityIndicator = UIActivityIndicatorView()
//Suppose you want to load some data from the network in this view controller
override func viewDidLoad() {
super.viewDidLoad()
showActivityIndicator() //Wow you can use this here!!!
getSomeData { data in
//do stuff with data
self.hideActivityIndicator()
}
}
What I suggest is to implement them as two separated methods, also to add them into extension of UIViewController, as follows:
UIViewController extension:
extension UIViewController {
func showActivityIndicator() {
let activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
activityIndicator.backgroundColor = UIColor(red:0.16, green:0.17, blue:0.21, alpha:1)
activityIndicator.layer.cornerRadius = 6
activityIndicator.center = view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = .WhiteLarge
activityIndicator.startAnimating()
//UIApplication.shared.beginIgnoringInteractionEvents()
activityIndicator.tag = 100 // 100 for example
// before adding it, you need to check if it is already has been added:
for subview in view.subviews {
if subview.tag == 100 {
print("already added")
return
}
}
view.addSubview(activityIndicator)
}
func hideActivityIndicator() {
let activityIndicator = view.viewWithTag(100) as? UIActivityIndicatorView
activityIndicator?.stopAnimating()
// I think you forgot to remove it?
activityIndicator?.removeFromSuperview()
//UIApplication.shared.endIgnoringInteractionEvents()
}
}
I assume that you want to always show/hide the activityIndicator it to ViewController.view, if it is not, you might need let it an activityIndicator of UIView instead of UIViewController.
Usage:
For example, consider that you have two IBActions, the first shows the activity indicator and the other one hides it, they should be like:
#IBAction func show(sender: AnyObject) {
showActivityIndicator()
}
#IBAction func hide(sender: AnyObject) {
hideActivityIndicator()
}
I found it best just to set a 'tag' to the activity indicator and then reference to that when stopping the animation, using one function to hide and one to show as Ahmad suggested. Ahmad F's answer and Guillermo's answer seem good as well.
Show/hide functions inside my Utils.swift file:
static func showActivityIndicator(view: UIView, targetVC: UIViewController) {
var activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView()
activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
activityIndicator.backgroundColor = UIColor(red:0.16, green:0.17, blue:0.21, alpha:1)
activityIndicator.layer.cornerRadius = 6
activityIndicator.center = targetVC.view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.whiteLarge
activityIndicator.tag = 1
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.shared.beginIgnoringInteractionEvents()
}
static func hideActivityIndicator(view: UIView) {
let activityIndicator = view.viewWithTag(1) as? UIActivityIndicatorView
activityIndicator?.stopAnimating()
activityIndicator?.removeFromSuperview()
UIApplication.shared.endIgnoringInteractionEvents()
}
Calling show function:
Utils.showActivityIndicator(view: view, targetVC: self)
Calling hide function:
Utils.hideActivityIndicator(view: view)

Activity indicator not showing when executed

I am trying to display an activity indicator when the user hits the login button. If I put the startActivityIndicator() code in viewDidLoad() it shows on the screen exactly as expected. When I execute it as the first step in btnSignIn() it never appears. A little lost, so i'm hoping the Stack guru's can help...
// Here are the variable declarations
var activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView()
var loadingView: UIView = UIView()
var viewCenter:CGPoint!
#IBAction func btnSignIn(sender: AnyObject) {
startActivityIndicator()
if validateEmailAddress(txtEmailAddress.text!) == false {
stopActivityIndicator(self.loadingView)
return
}
if validatePassword(txtPassword.text!) == false {
stopActivityIndicator(self.loadingView)
return
}
PFUser.logInWithUsernameInBackground(txtEmailAddress.text!, password:txtPassword.text!) {
(user: PFUser?, error: NSError?) -> Void in
if user != nil {
// Successful login.
self.txtPassword.resignFirstResponder()
self.txtEmailAddress.resignFirstResponder()
self.getUserInfo()
} else {
self.stopActivityIndicator(self.loadingView)
// The login failed. Display alert.
self.displayAlert("Whoops!", message: "Email or Password are incorrect.")
}
}
}
func startActivityIndicator() {
loadingView.frame = CGRectMake(0, 0, 80, 80)
loadingView.center = viewCenter
print(viewCenter)
loadingView.backgroundColor = UIColorFromRGB("444444", alpha: 0.7)
loadingView.clipsToBounds = true
loadingView.layer.cornerRadius = 10
activityIndicator.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.WhiteLarge
activityIndicator.center = CGPointMake(loadingView.frame.size.width / 2, loadingView.frame.size.height / 2);
view.addSubview(loadingView)
loadingView.addSubview(activityIndicator)
UIApplication.sharedApplication().beginIgnoringInteractionEvents()
activityIndicator.startAnimating()
}
func stopActivityIndicator(uiView: UIView) {
activityIndicator.stopAnimating()
loadingView.removeFromSuperview()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
}
Using my delay utility (see here: https://stackoverflow.com/a/24318861/341994), rewrite like this:
#IBAction func btnSignIn(sender: AnyObject) {
startActivityIndicator()
delay(0.1) {
if validateEmailAddress(txtEmailAddress.text!) == false {
// ... everything else goes here ...
}
}
The delay gives the activity indicator a chance to appear and start spinning.

How to create a new class from UIVisualEffectView and UIActivityIndicatorView

I've made a busy indicator that works really well, so long as it's in the ViewController I want to display the indicator in. I attempted to move this over to a new class of type UIView, but can't get anything to appear in the ViewController.
This is the working code, that is not it's own type:
//Create a busy indicator that can be shown by changing a single variable
var blur: UIVisualEffectView?
var spinner: UIActivityIndicatorView?
var showingActivity: Bool = false {
didSet{
switch showingActivity {
case true:
blur = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Dark))
blur!.frame = CGRectMake(100, 100, 150, 150)
blur!.center = self.view.center
blur!.layer.cornerRadius = 10
blur!.clipsToBounds = true
self.view.addSubview(blur!)
spinner = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)
spinner!.frame = CGRectMake(0, 0, 50, 50)
spinner!.center = self.view.center
spinner!.hidesWhenStopped = true
spinner!.startAnimating()
self.view.addSubview(spinner!)
UIApplication.sharedApplication().networkActivityIndicatorVisible = true //network activity option
case false:
blur?.removeFromSuperview()
spinner?.removeFromSuperview()
blur = nil
spinner = nil
UIApplication.sharedApplication().networkActivityIndicatorVisible = false //network activity option
default: break
}
}
}
func toggleNetworkActivity() {
showingActivity = !showingActivity
}
This is the code that doesn't seem to create anything.
class busy : UIView {
var blur = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Dark))
var spinner = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)
init() {
let frame = CGRect(x: 0, y: 0, width: 300, height: 300)
super.init(frame: frame)
blur.frame = CGRectMake(100, 100, 150, 150)
blur.center = self.center
blur.layer.cornerRadius = 10
blur.clipsToBounds = true
spinner.frame = CGRectMake(0, 0, 50, 50)
spinner.center = self.center
spinner.hidesWhenStopped = true
spinner.startAnimating()
self.setNeedsDisplay()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And in ViewDidLoad:
var test = busy()
test.center = self.view.center
self.view.addSubview(test)
Figured it out. Here is the code, if anyone is interested. But, is this the right way to do this kind of task?
class busy : UIView {
private var blur = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Dark))
private var spinner = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)
var isActive: Bool = false
override init (frame : CGRect) {
super.init(frame : frame)
}
required init(coder aDecoder: NSCoder) {
fatalError("This class does not support NSCoding")
}
func startActivity() {
let x = UIScreen.mainScreen().bounds.width/2
let y = UIScreen.mainScreen().bounds.height/2
blur.frame = CGRectMake(100, 100, 150, 150)
blur.layer.cornerRadius = 10
blur.center = CGPoint(x: x, y: y)
blur.clipsToBounds = true
spinner.frame = CGRectMake(0, 0, 50, 50)
spinner.hidden = false
spinner.center = CGPoint(x: x, y: y)
spinner.startAnimating()
super.addSubview(blur)
super.addSubview(spinner)
isActive = true
}
func stopActivity() {
blur.removeFromSuperview()
spinner.removeFromSuperview()
isActive = false
}
}
And then in use:
#IBAction func toggle() {
if test.isActive {
test.stopActivity()
test.removeFromSuperview()
println("Stopping")
} else {
test.startActivity()
self.view.addSubview(test)
println("Starting")
}
}

Resources