如何在细胞中显示进展?

我在didSelectRowAt indexPath:使用代码didSelectRowAt indexPath:在单元格上单击启动下载文件,我在cellForRowAt indexPath:使用代码cellForRowAt indexPath:显示现在下载文件的进度。

 class TableViewController: UITableViewController { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return (mainArray[buttonIndex] as AnyObject).count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: String(format: "cell", indexPath.row), for: indexPath) let circularProgressViewForCell = FFCircularProgressView(frame: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(24), height: CGFloat(24))) cell.accessoryView = circularProgressViewForCell circularProgressViewForCell.isHidden = true DownloadManager.shared.onProgress = { (progress) in circularProgressViewForCell.isHidden = false OperationQueue.main.addOperation { circularProgressViewForCell.progress = CGFloat(progress) if (cell.accessoryView as! FFCircularProgressView?)?.progress == 1.0 { print("FFCircularProgressView") (cell.accessoryView as! FFCircularProgressView?)?.circularState = .completed } } } } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let url = URL(string: "link")! let downloadTaskLocal = DownloadManager.shared.activate().downloadTask(with: url) downloadTaskLocal.resume() } } 

我在DownloadManager创建URLSession:

 import Foundation class DownloadManager : NSObject, URLSessionDelegate, URLSessionDownloadDelegate { static var shared = DownloadManager() typealias ProgressHandler = (Float) -> () var onProgress : ProgressHandler? { didSet { if onProgress != nil { let _ = activate() } } } override private init() { super.init() } func activate() -> URLSession { let config = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier!).background") return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue()) } private func calculateProgress(session : URLSession, completionHandler : @escaping (Float) -> ()) { session.getTasksWithCompletionHandler { (tasks, uploads, downloads) in let progress = downloads.map({ (task) -> Float in if task.countOfBytesExpectedToReceive > 0 { return Float(task.countOfBytesReceived) / Float(task.countOfBytesExpectedToReceive) } else { return 0.0 } }) completionHandler(progress.reduce(0.0, +)) } } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL){ let fileName = downloadTask.originalRequest?.url?.lastPathComponent let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) let documentDirectoryPath:String = path[0] let fileManager = FileManager() var destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appending("/\(id)")) do { try fileManager.createDirectory(at: destinationURLForFile, withIntermediateDirectories: true, attributes: nil) destinationURLForFile.appendPathComponent(String(describing: fileName!)) try fileManager.moveItem(at: location, to: destinationURLForFile) }catch(let error){ print(error) } } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { if totalBytesExpectedToWrite > 0 { if let onProgress = onProgress { calculateProgress(session: session, completionHandler: onProgress) } let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite) debugPrint("Progress \(downloadTask) \(progress)") } } func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { debugPrint("Task completed: \(task), error: \(error)") } } 

我想点击单元格,开始文件下载并显示所选单元格中下载文件的进度。 我可以在didSelectRowAt indexPath:创建我的progressView didSelectRowAt indexPath:但它不是最好的解决方案,因为用户可能会在我的应用程序中移动上一个或下一个控制器,或者可能在下载处于活动状态时隐藏应用程序。 当用户在TableViewController中返回时,我更新了cellForRowAt indexPath:进度cellForRowAt indexPath:

问题:当我开始下载文件时,我的进度不会显示在选定的行中。 进度显示在屏幕外的行中。 当我滚动tableView时,我看到所有单元格中的进度都在变化。 如何解决它并显示所选单元格的进度?

UPD

 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { var item = self.items[indexPath.row] if item.downloadStatus == .inProgress || item.downloadStatus == .completed { print("video already downloaded") } else { let url = URL(string: "link\(indexPath.row)")! let int = self.tableId + indexPath.row // table0 = 1000, table1 = 2000 and etc. DownloadManager.shared.identifier = int let downloadTaskLocal = DownloadManager.shared.activate().downloadTask(with: url) downloadTaskLocal.resume() DownloadManager.shared.onProgress = { (row, progress) in var row = row row = row - self.tableId DispatchQueue.main.async { let indexpath = IndexPath.init(row: row, section: 0) let cell = self.tableView.cellForRow(at: indexpath) print("downloading for cell \(String(describing: cell?.tag))") if progress <= 1.0 { let progressRing = cell?.accessoryView as! FFCircularProgressView progressRing.progress = CGFloat(progress) if progress == 1.0 { item.downloadStatus = .completed cell?.textLabel?.text = "Download Complete" } else { cell?.textLabel?.text = "Download In Progress" } } } } 

UPD 1

 import UIKit import StoreKit enum DownloadStatus { case none case inProgress case completed case failed } struct item { var title : String! let link = "" var downloadStatus : DownloadStatus = .none init(title: String) { self.title = title } } var id = "" class MasterViewController: UITableViewController { var mainArray:[[Any]] = [] var index = 0 var buttonIndex = 0 var objects = [Any]() var items = [item]() var tableId = 0 override func viewDidLoad() { super.viewDidLoad() items.append(item(title: "Video 1")) items.append(item(title: "Video 2")) items.append(item(title: "Video 3")) items.append(item(title: "Video 4")) items.append(item(title: "Video 5")) items.append(item(title: "Video 6")) items.append(item(title: "Video 7")) items.append(item(title: "Video 8")) items.append(item(title: "Video 9")) items.append(item(title: "Video 10")) items.append(item(title: "Video 11")) items.append(item(title: "Video 12")) if buttonIndex == 0 { id = "id0" tableId = 1000 } else if buttonIndex == 1 { id = "id1" tableId = 2000 } mainArray = [array0,array1,array2,array3,array4,array5,array6] NotificationCenter.default.addObserver(self, selector: #selector(self.onApplicationDidBecomeActiveNotification), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil) } func onApplicationDidBecomeActiveNotification(notification:Notification) { self.tableView.reloadData() } override func viewWillAppear(_ animated: Bool) { self.tableView.reloadData() } override func viewDidAppear(_ animated: Bool) { self.tableView.reloadData() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return (mainArray[buttonIndex] as AnyObject).count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: String(format: "cell", indexPath.row), for: indexPath) let item = items[indexPath.row] print(item.downloadStatus) if item.downloadStatus != .completed { let progressRing = FFCircularProgressView(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) cell.tag = indexPath.row cell.accessoryType = UITableViewCellAccessoryType.none cell.accessoryView = progressRing } else { cell.accessoryView = nil } return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { var item = self.items[indexPath.row] if item.downloadStatus == .inProgress || item.downloadStatus == .completed { print("video already downloaded") } else { let url = URL(string: "link\(indexPath.row + 1).mp3")! let int = self.tableId + indexPath.row let downloadManager = DownloadManager() downloadManager.identifier = int downloadManager.folderPath = id let downloadTaskLocal = downloadManager.activate().downloadTask(with: url) downloadTaskLocal.resume() downloadManager.onProgress = { (row, progress) in var row = row row = row - self.tableId DispatchQueue.main.async { let indexpath = IndexPath.init(row: row, section: 0) let cell = self.tableView.cellForRow(at: indexpath) print("downloading for cell \(String(describing: cell?.tag))") if progress <= 1.0 { let progressRing = FFCircularProgressView(frame: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(24), height: CGFloat(24))) cell?.accessoryView = progressRing progressRing.progress = CGFloat(progress) if progress == 1.0 { item.downloadStatus = .completed } } } } } 

FirstViewController的代码

 import UIKit import StoreKit class TableViewController: UITableViewController { let array = ["","","","","","",""] override func viewDidLoad() { super.viewDidLoad() } override func viewWillAppear(_ animated: Bool) { let newBackButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) self.navigationItem.backBarButtonItem = newBackButton self.tableView.reloadData() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return array.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell cell.button.tag = indexPath.row cell.selectionStyle = .none return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { } override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 165.0 } public override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 12.0 } override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let headerView = UIView() headerView.backgroundColor = UIColor.clear return headerView } // MARK: - Navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if (segue.destination is MasterViewController) { if let button = sender as? UIButton { (segue.destination as? MasterViewController)?.buttonIndex = button.tag } } } } 

TableViewCell中的代码

 import UIKit class TableViewCell: UITableViewCell { @IBOutlet weak var button: UIButton! override func awakeFromNib() { super.awakeFromNib() } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) } } 

@Artem我在DownloadManager中添加了一个属性,作为’identifier’(int)。 这将保存indexpath.row值。

在ProgressHandler完成块中发回此标识符值。

附上上述更改的更新代码。

 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) DownloadManager.shared.onProgress = { (row, progress) in print("Downloading for \(row) with progress \(progress)") } return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let url = URL(string: "link")! DownloadManager.shared.identifier = indexPath.row let downloadTaskLocal = DownloadManager.shared.activate().downloadTask(with: url) downloadTaskLocal.resume() } 

在您的DownloadManager中

class DownloadManager:NSObject,URLSessionDelegate,URLSessionDownloadDelegate {

 static var shared = DownloadManager() var identifier : Int = -1 typealias ProgressHandler = (Int, Float) -> () var onProgress : ProgressHandler? { didSet { if onProgress != nil { let _ = activate() } } } override private init() { super.init() } func activate() -> URLSession { let config = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier!).background") return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue()) } private func calculateProgress(session : URLSession, completionHandler : @escaping (Int, Float) -> ()) { session.getTasksWithCompletionHandler { (tasks, uploads, downloads) in let progress = downloads.map({ (task) -> Float in if task.countOfBytesExpectedToReceive > 0 { return Float(task.countOfBytesReceived) / Float(task.countOfBytesExpectedToReceive) } else { return 0.0 } }) completionHandler(self.identifier, progress.reduce(0.0, +)) } } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL){ let fileName = downloadTask.originalRequest?.url?.lastPathComponent let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) let documentDirectoryPath:String = path[0] let fileManager = FileManager() var destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appending("/\(id)")) do { try fileManager.createDirectory(at: destinationURLForFile, withIntermediateDirectories: true, attributes: nil) destinationURLForFile.appendPathComponent(String(describing: fileName!)) try fileManager.moveItem(at: location, to: destinationURLForFile) }catch(let error){ print(error) } } func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { if totalBytesExpectedToWrite > 0 { if let onProgress = onProgress { calculateProgress(session: session, completionHandler: onProgress) } let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite) debugPrint("Progress \(downloadTask) \(progress)") } } func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { debugPrint("Task completed: \(task), error: \(String(describing: error))") } } 

更新的答案

我创建了一个简单的项目来演示UITableViewCell上的下载进度更新。

https://github.com/mcabasheer/table-cell-progress-bar/tree/master

在此处输入图像描述

希望这可以帮助 :)

您的案例中的问题是细胞的重复使用。
tableView(: cellForRowAt:)您必须管理用户从具体单元格下载而不是下载的事实。
您的DownloadManager似乎不知道您正在下载哪个URL(单元格)。
例如,保留所选url的数组。

对于渐进式下载并向tableview显示,您必须按照以下步骤操作:

步骤1 :单击单元格时,将其索引存储在数组中。 (我们将该名称命名为 – arrDownloads

步骤2 :在cellForRowAtIndexPath检查arrDownloads包含当前索引路径

步骤3 :如果当前索引在cellForRowAtIndexPath中位于arrDownloads内, arrDownloads当前索引的URL传递给下载管理器。 (确保您有另一个URL数组来下载图像(文件))

这可能有所帮助。

我想,你在tableView的标题中设置你的进度。 滚动tableview时可以看到进度。