如何删除进度条圈中的 CAShapeLayer
How do I remove a CAShapeLayer in progressbar circle
我有以下代码,我正在执行它来下载带有进度圈的 PDF。
它对我有用,首先我检查文件是否已保存在 "Documents" 目录中,如果是,我只显示 PDF,如果尚未加载 pdf 文件,则 begindDownloadFile ()
lass ViewController: UIViewController, URLSessionDownloadDelegate {
@IBOutlet weak var pdfView: PDFView!
let urlString = "https://d0.awsstatic.com/whitepapers/KMS-Cryptographic-Details.pdf"
let shapeLayer = CAShapeLayer()
let percentageLabel: UILabel = {
let label = UILabel()
label.text = "Descargar"
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 16)
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(percentageLabel)
percentageLabel.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
percentageLabel.center = view.center
//start drawing circle
let center = view.center
//create the track layer, the softer color underneath the bar that it is going to fill
let trackLayer = CAShapeLayer()
let circularPath = UIBezierPath(arcCenter: .zero, radius: 100, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
trackLayer.path = circularPath.cgPath
trackLayer.strokeColor = UIColor.lightGray.cgColor
trackLayer.lineWidth = 10 //the width of the bar
trackLayer.fillColor = UIColor.clear.cgColor //amek the middle area have clear color
trackLayer.lineCap = kCALineCapRound //this to make the bar has rounded corner
trackLayer.position = center
trackLayer.opacity = 1
view.layer.addSublayer(trackLayer)
// let circularPath = UIBezierPath(arcCenter: center, radius: 100, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true) //start angle like this to have the bar start at 12 o'clock
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.lineWidth = 10 //the width of the bar
shapeLayer.fillColor = UIColor.clear.cgColor //amek the middle area have clear color
shapeLayer.lineCap = kCALineCapRound //this to make the bar has rounded corner
shapeLayer.strokeEnd = 0
shapeLayer.position = center
shapeLayer.transform = CATransform3DMakeRotation(-CGFloat.pi / 2, 0, 0, 1)
view.layer.addSublayer(shapeLayer)
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
let myUrl = URL(string: urlString)
// then lets create your document folder url
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
// lets create your destination file url
let destinationUrl = documentsDirectoryURL.appendingPathComponent((myUrl?.lastPathComponent)!)
print(destinationUrl)
if FileManager.default.fileExists(atPath: destinationUrl.path) {
print("The file already exists at path")
// hidden label and remove sublayers (circle)
//self.percentageLabel.isHidden = true
//shapeLayer.removeFromSuperlayer()
//trackLayer.removeFromSuperlayer()
trackLayer.removeFromSuperlayer()
/************** show pdf ****************/
let pdfUrl = destinationUrl.path
let rutafile = URL(fileURLWithPath: pdfUrl)
print(pdfUrl)
if let document = PDFDocument(url: rutafile) {
self.pdfView.autoScales = true
self.pdfView.document = document
}
/************** show pdf ****************/
} else{
begindDownloadFile()
}
} // end DidLoad
//the require func for URLSessionDownloadDelegate delegate
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("finish downloading file")
}
//optional func from the delegate URLSessionDownloadDelegate
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
// print(totalBytesWritten, totalBytesExpectedToWrite)
let percentage = CGFloat(totalBytesWritten) / CGFloat(totalBytesExpectedToWrite)
print("percentage : ", percentage)
//this need to be in the main thread because the url session downloading is not on the main thread, so if without DispatchQueue.main, then the UI wont update
DispatchQueue.main.async {
self.percentageLabel.text = "\(Int(percentage * 100))%"
self.shapeLayer.strokeEnd = percentage
}
}
private func begindDownloadFile(){
//this fix the bar going back and forth
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)
/****/
// then lets create your document folder url
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
// lets create your destination file url
let destinationUrl = documentsDirectoryURL.appendingPathComponent(url.lastPathComponent)
print(destinationUrl)
// you can use NSURLSession.sharedSession to download the data asynchronously
URLSession.shared.downloadTask(with: url, completionHandler: { (location, response, error) -> Void in
guard let location = location, error == nil else { return }
do {
// after downloading your file you need to move it to your destination url
try FileManager.default.moveItem(at: location, to: destinationUrl)
print("File moved to documents folder")
print("file has already been downloaded")
DispatchQueue.main.async {
// escondemos label y removemos sublayers (circulo)
self.percentageLabel.isHidden = true
//self.shapeLayer.removeFromSuperlayer()
//self.trackLayer.removeFromSuperlayer()
//self.shapeLayer.removeAllAnimations()
self.shapeLayer.opacity = 0
/************** show pdf ****************/
let pdfUrl = destinationUrl.path
let rutafile = URL(fileURLWithPath: pdfUrl)
print(pdfUrl)
if let document = PDFDocument(url: rutafile) {
self.pdfView.autoScales = true
self.pdfView.document = document
}
/************** show pdf ****************/
}
} catch let error as NSError {
print(error.localizedDescription)
}
}).resume()
/***/
downloadTask.resume()
}
fileprivate func animateCircle() {
let basicAnimation = CABasicAnimation(keyPath: "strokeEnd") //animate the shapeLayer.strokeEnd
basicAnimation.toValue = 1
basicAnimation.duration = 2
//need these 2 lines to make the bar stopped at the final point, if not it will be removed upon completion
basicAnimation.fillMode = kCAFillModeForwards
basicAnimation.isRemovedOnCompletion = false
shapeLayer.add(basicAnimation,forKey: "customString")
}
@objc private func handleTap(){
print("animate here")
//begindDownloadFile()
// animateCircle()//custom string for forKey value, not sure where will use it later
}
}
我的问题是我无法隐藏圆圈,我已经在 DispatchQueue.main.async
中尝试使用 self.shapeLayer.removeFromSuperlayer ()
但它对我不起作用,使用 self.shapeLayer.opacity = 0
如有任何建议,我将不胜感激
你的 shapeLayer 是红色的,你的 trackLayer 是灰色的。您在图像中显示的是您的 shapeLayer 已删除,但您的 trackLayer 仍然存在,您还需要调用 removeFromSuperlayer。
同时将 trackLayer 的初始声明移出 viewDidLoad() 并将其与 shapeLayer 声明放在一起,以便您可以在该方法之外访问它。即:
let urlString = "https://d0.awsstatic.com/whitepapers/KMS-Cryptographic-Details.pdf"
let shapeLayer = CAShapeLayer()
let trackLayer = CAShapeLayer()
我有以下代码,我正在执行它来下载带有进度圈的 PDF。
它对我有用,首先我检查文件是否已保存在 "Documents" 目录中,如果是,我只显示 PDF,如果尚未加载 pdf 文件,则 begindDownloadFile ()
lass ViewController: UIViewController, URLSessionDownloadDelegate {
@IBOutlet weak var pdfView: PDFView!
let urlString = "https://d0.awsstatic.com/whitepapers/KMS-Cryptographic-Details.pdf"
let shapeLayer = CAShapeLayer()
let percentageLabel: UILabel = {
let label = UILabel()
label.text = "Descargar"
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 16)
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(percentageLabel)
percentageLabel.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
percentageLabel.center = view.center
//start drawing circle
let center = view.center
//create the track layer, the softer color underneath the bar that it is going to fill
let trackLayer = CAShapeLayer()
let circularPath = UIBezierPath(arcCenter: .zero, radius: 100, startAngle: 0, endAngle: 2 * CGFloat.pi, clockwise: true)
trackLayer.path = circularPath.cgPath
trackLayer.strokeColor = UIColor.lightGray.cgColor
trackLayer.lineWidth = 10 //the width of the bar
trackLayer.fillColor = UIColor.clear.cgColor //amek the middle area have clear color
trackLayer.lineCap = kCALineCapRound //this to make the bar has rounded corner
trackLayer.position = center
trackLayer.opacity = 1
view.layer.addSublayer(trackLayer)
// let circularPath = UIBezierPath(arcCenter: center, radius: 100, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true) //start angle like this to have the bar start at 12 o'clock
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.lineWidth = 10 //the width of the bar
shapeLayer.fillColor = UIColor.clear.cgColor //amek the middle area have clear color
shapeLayer.lineCap = kCALineCapRound //this to make the bar has rounded corner
shapeLayer.strokeEnd = 0
shapeLayer.position = center
shapeLayer.transform = CATransform3DMakeRotation(-CGFloat.pi / 2, 0, 0, 1)
view.layer.addSublayer(shapeLayer)
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
let myUrl = URL(string: urlString)
// then lets create your document folder url
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
// lets create your destination file url
let destinationUrl = documentsDirectoryURL.appendingPathComponent((myUrl?.lastPathComponent)!)
print(destinationUrl)
if FileManager.default.fileExists(atPath: destinationUrl.path) {
print("The file already exists at path")
// hidden label and remove sublayers (circle)
//self.percentageLabel.isHidden = true
//shapeLayer.removeFromSuperlayer()
//trackLayer.removeFromSuperlayer()
trackLayer.removeFromSuperlayer()
/************** show pdf ****************/
let pdfUrl = destinationUrl.path
let rutafile = URL(fileURLWithPath: pdfUrl)
print(pdfUrl)
if let document = PDFDocument(url: rutafile) {
self.pdfView.autoScales = true
self.pdfView.document = document
}
/************** show pdf ****************/
} else{
begindDownloadFile()
}
} // end DidLoad
//the require func for URLSessionDownloadDelegate delegate
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("finish downloading file")
}
//optional func from the delegate URLSessionDownloadDelegate
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
// print(totalBytesWritten, totalBytesExpectedToWrite)
let percentage = CGFloat(totalBytesWritten) / CGFloat(totalBytesExpectedToWrite)
print("percentage : ", percentage)
//this need to be in the main thread because the url session downloading is not on the main thread, so if without DispatchQueue.main, then the UI wont update
DispatchQueue.main.async {
self.percentageLabel.text = "\(Int(percentage * 100))%"
self.shapeLayer.strokeEnd = percentage
}
}
private func begindDownloadFile(){
//this fix the bar going back and forth
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)
/****/
// then lets create your document folder url
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
// lets create your destination file url
let destinationUrl = documentsDirectoryURL.appendingPathComponent(url.lastPathComponent)
print(destinationUrl)
// you can use NSURLSession.sharedSession to download the data asynchronously
URLSession.shared.downloadTask(with: url, completionHandler: { (location, response, error) -> Void in
guard let location = location, error == nil else { return }
do {
// after downloading your file you need to move it to your destination url
try FileManager.default.moveItem(at: location, to: destinationUrl)
print("File moved to documents folder")
print("file has already been downloaded")
DispatchQueue.main.async {
// escondemos label y removemos sublayers (circulo)
self.percentageLabel.isHidden = true
//self.shapeLayer.removeFromSuperlayer()
//self.trackLayer.removeFromSuperlayer()
//self.shapeLayer.removeAllAnimations()
self.shapeLayer.opacity = 0
/************** show pdf ****************/
let pdfUrl = destinationUrl.path
let rutafile = URL(fileURLWithPath: pdfUrl)
print(pdfUrl)
if let document = PDFDocument(url: rutafile) {
self.pdfView.autoScales = true
self.pdfView.document = document
}
/************** show pdf ****************/
}
} catch let error as NSError {
print(error.localizedDescription)
}
}).resume()
/***/
downloadTask.resume()
}
fileprivate func animateCircle() {
let basicAnimation = CABasicAnimation(keyPath: "strokeEnd") //animate the shapeLayer.strokeEnd
basicAnimation.toValue = 1
basicAnimation.duration = 2
//need these 2 lines to make the bar stopped at the final point, if not it will be removed upon completion
basicAnimation.fillMode = kCAFillModeForwards
basicAnimation.isRemovedOnCompletion = false
shapeLayer.add(basicAnimation,forKey: "customString")
}
@objc private func handleTap(){
print("animate here")
//begindDownloadFile()
// animateCircle()//custom string for forKey value, not sure where will use it later
}
}
我的问题是我无法隐藏圆圈,我已经在 DispatchQueue.main.async
中尝试使用 self.shapeLayer.removeFromSuperlayer ()
但它对我不起作用,使用 self.shapeLayer.opacity = 0
如有任何建议,我将不胜感激
你的 shapeLayer 是红色的,你的 trackLayer 是灰色的。您在图像中显示的是您的 shapeLayer 已删除,但您的 trackLayer 仍然存在,您还需要调用 removeFromSuperlayer。
同时将 trackLayer 的初始声明移出 viewDidLoad() 并将其与 shapeLayer 声明放在一起,以便您可以在该方法之外访问它。即:
let urlString = "https://d0.awsstatic.com/whitepapers/KMS-Cryptographic-Details.pdf"
let shapeLayer = CAShapeLayer()
let trackLayer = CAShapeLayer()