• Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

The final effect to be completed:

Generally speaking, the progress bar is used to monitor the download progress. Next, you need to simulate the download process and let the progress bar change according to the download progress. Create a method to download the file, using URLSession to observe the download. Here need to follow URLSessionDownloadDelegate, and implement proxy approach, or complains.

func beginDownloadingFile() {
        let configuration = URLSessionConfiguration.default
        let operationQueue = OperationQueue()
        let urlSession = URLSession(configuration: configuration, delegate: self, delegateQueue: operationQueue)
        
        guard let url = URL(string: urlString) else { return }
        let downloadTask = urlSession.downloadTask(with: url)
        downloadTask.resume()
    }
Copy the code

Then in the proxy method of the URLSession, calculate the percentage of data that has been written and the total number of data that needs to be written, and change the strokeEnd of the shapeLayer based on that percentage. When you change the strokeEnd here, you have to put it on the main thread, otherwise the view won’t change.

 func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        let percentage = CGFloat(totalBytesWritten) / CGFloat(totalBytesExpectedToWrite)
        
        DispatchQueue.main.async {
            self.shapeLayer.strokeEnd = percentage
        }
        
        print(percentage)
    }
Copy the code

Next you need to create a label to display in the middle of a shapelayer. Create a UILabel for VC to hold, with the text Start, the text centered, the font size bold 32 points, and the font color black.

   let percentageLabel: UILabel = {
        let label = UILabel()
        label.text = "Start"
        label.textAlignment = .center
        label.font = UIFont.boldSystemFont(ofSize: 32)
        label.textColor = .black
        return label
    }()
    
Copy the code

In the view, add percentageLabel as the subview of the view, set the frame of the label, and put it in the center of the view.

 view.addSubview(percentageLabel)
 percentageLabel.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
 percentageLabel.center = view.center
Copy the code

Next you need to change the percentageLabel text to the appropriate percentage at the start of the download task. And that’s where I just set strokeEnd in the URLSession proxy method and just set percentageLabel text. Note here that the text also needs to be set inside the main thread.

        DispatchQueue.main.async {
            self.percentageLabel.text = "\(Int(percentage * 100))%"
            self.shapeLayer.strokeEnd = percentage
        }
Copy the code

At this point the progress bar will follow the progress of the download and show a white score in the middle.

Complete code:

import UIKit class ViewController: UIViewController,URLSessionDownloadDelegate { let shapeLayer = CAShapeLayer() let percentageLabel: UILabel = { let label = UILabel() label.text = "Start" label.textAlignment = .center label.font = UIFont.boldSystemFont(ofSize: 32) label.textColor = .black return label }() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. view.addSubview(percentageLabel) percentageLabel.frame = CGRect(x: 0, y: 0, width: 100, height: 100) percentageLabel.center = view.center let circularPath = UIBezierPath(arcCenter: .zero, radius: 100, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true) let trackLayer = CAShapeLayer() trackLayer.path = circularPath.cgPath trackLayer.strokeColor = UIColor.lightGray.cgColor trackLayer.lineWidth = 10 trackLayer.position = view.center trackLayer.fillColor = UIColor.clear.cgColor trackLayer.lineCap = .round view.layer.addSublayer(trackLayer) shapeLayer.path = circularPath.cgPath shapeLayer.strokeEnd = 0 shapeLayer.position = view.center shapeLayer.strokeColor = UIColor.red.cgColor shapeLayer.lineWidth = 10 shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.lineCap = .round shapeLayer.transform = CATransform3DMakeRotation(-CGFloat.pi / 2, 0, 0, 1) view.layer.addSublayer(shapeLayer) view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap))) } let urlString = "https://firebasestorage.googleapis.com/v0/b/firestorechat-e64ac.appspot.com/o/intermediate_training_rec.mp4?alt=media&t oken=e20261d0-7219-49d2-b32d-367e1606500c" func beginDownloadingFile() { shapeLayer.strokeEnd = 0 let configuration = URLSessionConfiguration.default let operationQueue = OperationQueue() let urlSession = URLSession(configuration: configuration, delegate: self, delegateQueue: operationQueue) guard let url = URL(string: urlString) else { return } let downloadTask = urlSession.downloadTask(with: url) downloadTask.resume() } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { let percentage = CGFloat(totalBytesWritten) / CGFloat(totalBytesExpectedToWrite) DispatchQueue.main.async { self.percentageLabel.text = "\(Int(percentage * 100))%" self.shapeLayer.strokeEnd = percentage } print(percentage) } @objc func handleTap() { beginDownloadingFile() // let basicAnimation = CABasicAnimation(keyPath: "strokeEnd") // basicAnimation.toValue = 1 // basicAnimation.duration = 2 // basicAnimation.fillMode = .forwards // basicAnimation.isRemovedOnCompletion = false // shapeLayer.add(basicAnimation, forKey: "stokeAnimation") } }Copy the code