[英]UIProgressView with multiple progress
標准的UIProgressView
僅顯示一個進度,如果您嘗試捕獲多個項目的進度,您將擁有Progress
/ NSProgress
對象的層次結構。 例如,如果上傳五個文件,您有五個Progress
對象,每個上傳一個,然后有第六個NSProgress
, UIProgressView
觀察到,其他五個作為子級。 請參閱NSProgress 類參考中的創建進度對象樹。 有關示例,請參見https://stackoverflow.com/a/36616538/1271826 。
如果您想要一個進度視圖來直觀地表示單個NSProgress
的相應進度,則您必須自己執行此操作(或找到執行此操作的第三方控件)。 但是標准的UIProgressView
不會為你做這件事。
但這並不難。 例如,您可以創建一個水平堆棧視圖,為每個要跟蹤的NSProgress
添加一個UIProgressView
,將UIProgressView
子視圖的相應寬度設置為例如它們代表整個任務的任何百分比。
例如,這是一個水平堆棧視圖,其中包含三個UIProgressView
排列的子視圖:
話雖如此,我更喜歡標准的單一、統一的UIProgessView
因為用戶可以更輕松地看到它們的距離。 如果你有一系列這樣的進度視圖,真的很難直觀地看到“我還有多長時間”,因為你必須查看所有單獨的進度視圖並在頭腦中弄清楚(例如“第一個看起來像是 50 % 完成,第二個完成 66%,第三個完成 75% ......那么整個事情到底有多遠?!?”)。
無論如何,這里是我的 Swift 代碼來呈現上述內容。 我知道您正在尋找 Objective-C,但希望這足以說明可以在 Swift 或 Objective-C 中輕松實現的基本思想:
class MultiProgressView: UIStackView {
struct ProgressInfo {
let progressView: UIProgressView
let totalToken: NSKeyValueObservation
let progressToken: NSKeyValueObservation
}
var progressInfo = [ProgressInfo]()
var progressHandler: ((Double) -> Void)?
var widthConstraints: [NSLayoutConstraint]?
func add(_ progress: Progress, progressTintColor: UIColor = .blue, trackTintColor: UIColor? = nil) {
let progressView = UIProgressView(progressViewStyle: .bar)
progressView.translatesAutoresizingMaskIntoConstraints = false
progressView.progressTintColor = progressTintColor
progressView.trackTintColor = trackTintColor ?? progressTintColor.withAlphaComponent(0.5)
addArrangedSubview(progressView)
progressView.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 1)
progressView.observedProgress = progress
let totalToken = progress.observe(\.totalUnitCount) { [weak self] (_, _) in
self?.updateWidths()
}
let progressToken = progress.observe(\.completedUnitCount) { [weak self] (_, _) in
if let percent = self?.percent {
self?.progressHandler?(percent)
}
}
progressInfo.append(ProgressInfo(progressView: progressView, totalToken: totalToken, progressToken: progressToken))
updateWidths()
}
private func updateWidths() {
if let widthConstraints = self.widthConstraints {
removeConstraints(widthConstraints)
}
let totalUnitCount = self.totalUnitCount
guard totalUnitCount > 0 else { return }
widthConstraints = progressInfo.map { progressInfo in
let unitCount = progressInfo.progressView.observedProgress?.totalUnitCount ?? 0
return NSLayoutConstraint(item: progressInfo.progressView, attribute: .width, relatedBy: .equal, toItem: self, attribute: .width, multiplier: CGFloat(unitCount) / CGFloat(totalUnitCount), constant: 0)
}
DispatchQueue.main.async {
self.addConstraints(self.widthConstraints!)
}
}
var totalUnitCount: Int64 {
return progressInfo.reduce(Int64(0)) { $0 + ($1.progressView.observedProgress?.totalUnitCount ?? 0) }
}
var completedUnitCount: Int64 {
return progressInfo.reduce(Int64(0)) { $0 + ($1.progressView.observedProgress?.completedUnitCount ?? 0) }
}
var percent: Double {
return Double(completedUnitCount) / Double(totalUnitCount)
}
}
然后使用它:
override func viewDidLoad() {
super.viewDidLoad()
let download1 = Download(...)
let download2 = Download(...)
let download3 = Download(...)
mainProgressView.progressHandler = { [weak self] percent in
self?.checkIfDone(percent: percent)
}
mainProgressView.add(download1.progress, progressTintColor: .blue)
mainProgressView.add(download2.progress, progressTintColor: .green)
mainProgressView.add(download3.progress, progressTintColor: .red)
download1.startDownload()
download2.startDownload()
download3.startDownload()
}
private func checkIfDone(percent: Double) {
if percent == 1 {
print("done")
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.