-1

I have a UICollectionView that reads data from Firebase, and I want some kind of activity indicator while it's reading data.

I want the activity indicator to start running as soon as the UICollectionView tab in the TabBar is hit, and I want it to stop and the view/uicollectionView to load once loading from Firebase is done.

I saw this post:

Show Activity Indicator while data load in collectionView Swift

But I could not understand it fully because I did not know how to integrate my UICollectionView there.

EDIT:

This is my code that reads from Firebase:

self.ref = Database.database().reference()
            let loggedOnUserID = Auth.auth().currentUser?.uid


            if let currentUserID = loggedOnUserID
            {
                // Retrieve the products and listen for changes
                self.databaseHandle = self.ref?.child("Users").child(currentUserID).child("Products").observe(.childAdded, with:
                    { (snapshot) in

                        // Code to execute when new product is added
                        let prodValue = snapshot.value as? NSDictionary
                        let prodName = prodValue?["Name"] as? String ?? ""
                        let prodPrice = prodValue?["Price"] as? Double ?? -1
                        let prodDesc = prodValue?["Description"] as? String ?? ""
                        let prodURLS = prodValue?["MainImage"] as? String
                        let prodAmount = prodValue?["Amount"] as? Int ?? 0
                        let prodID = snapshot.key

                        let prodToAddToView = Product(name: prodName, price: prodPrice, currency: "NIS", description: prodDesc, location: "IL",
                                                      toSell: false, toBuy: false, owner: currentUserID, uniqueID: prodID, amount: prodAmount, mainImageURL: prodURLS)


                        self.products.append(prodToAddToView)
                        DispatchQueue.main.async
                            {
                                self.MyProductsCollection.reloadData()
                        }
                }
                ) // Closes observe function
Shivam Tripathi
  • 1,405
  • 3
  • 19
  • 37
Ofri
  • 289
  • 5
  • 17
  • You don't have to explicitly understand how to integrate activityIndicator with collectionView. You have to understand how do a UI update while doing a background task. – Nitish Feb 18 '18 at 18:31

2 Answers2

0
let activityView = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)

// waiy until main view shows 
override func viewDidAppear(_ animated: Bool) {

   super.viewDidAppear(animated)

   // create a hover view that covers all screen with opacity 0.4 to show a waiting action
    let fadeView:UIView = UIView()
    fadeView.frame = self.view.frame
    fadeView.backgroundColor = UIColor.whiteColor()
    fadeView.alpha = 0.4

   // add fade view to main view
    self.view.addSubview(fadeView)
 // add activity to main view
    self.view.addSubview(activityView)
    activityView.hidesWhenStopped = true
    activityView.center = self.view.center
// start animating activity view
    activityView.startAnimating()

  self.ref = Database.database().reference()
            let loggedOnUserID = Auth.auth().currentUser?.uid


            if let currentUserID = loggedOnUserID
            {
                // Retrieve the products and listen for changes
                self.databaseHandle = self.ref?.child("Users").child(currentUserID).child("Products").observeSingleEvent(.value, with:
                    { (snapshot) in

                        // Code to execute when new product is added
                        let prodValue = snapshot.value as? NSDictionary
                        let prodName = prodValue?["Name"] as? String ?? ""
                        let prodPrice = prodValue?["Price"] as? Double ?? -1
                        let prodDesc = prodValue?["Description"] as? String ?? ""
                        let prodURLS = prodValue?["MainImage"] as? String
                        let prodAmount = prodValue?["Amount"] as? Int ?? 0
                        let prodID = snapshot.key

                        let prodToAddToView = Product(name: prodName, price: prodPrice, currency: "NIS", description: prodDesc, location: "IL",
                                                      toSell: false, toBuy: false, owner: currentUserID, uniqueID: prodID, amount: prodAmount, mainImageURL: prodURLS)


                        self.products.append(prodToAddToView)
                        DispatchQueue.main.async
                            {
                                self.MyProductsCollection.reloadData()
                                  // remove the hover view as now we have data
                               fadeView.removeFromSuperview()
                               // stop animating the activity 
                               self.activityView.stopAnimating()
                        }
                }
                ) // Closes observe function
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
0

I mean UIActivityIndicatorView isn't hard to work with, you display it when fetching data, and stop it when done.

private lazy var indicator : UIActivityIndicatorView = { // here we simply declaring the indicator along some properties 
    let _indicator = UIActivityIndicatorView()
    // change the color
    _indicator.color = .black
    // when you call stopAnimation on this indicator, it will hide automatically
    _indicator.hidesWhenStopped = true
    return _indicator
}()

Now where you want to place it? you can either placed it into your parent's view, or into your navigationBar. (I choose to place into the right side of the navigationBar )

self.navigationItem.rightBarButtonItem = UIBarButtonItem.init(customView: indicator)

Now say you have this function that return data (via callbacks) from some apis.

// this callback emits data from a background queue
    func fetchPost(completion:@escaping(Array<Any>?, Error?) -> ()) {
        DispatchQueue.global(qos: .background).async {
           // ... do work 
             completion([], nil) // call your completionHandler based either error or data
        }
    }


/* now let's called that fetchPost function and load data into your 
  collectionView, but before let's started this indicator */


override func viewDidLoad() {
    super.viewDidLoad()
    self.navigationItem.rightBarButtonItem = UIBarButtonItem.init(customView: indicator)
    indicator.startAnimating()

    fetchPost { [weak self] (data, err) in
        // go to the main queue to update our collectionView
        // and stop the indicator
        DispatchQueue.main.async { [weak self] in
            // stop animation
            self?.indicator.startAnimating()
            // do something we have an error
            if let _err = err {}

            if let _data = data {
                // fill array for collectionView
                // reload the collectionView
                self?.collectionView?.reloadData()
            }
        }
    }
}
Lamour
  • 3,002
  • 2
  • 16
  • 28