2017-10-15 68 views
2

我怎样才能建立一个进度条,在iOS中有多个进度? 我不认为这是可能的UIProgressViewUIProgressView多进程

我期待这样的事情(UI只): progress bar 谢谢!

+0

Rob,你已经在评论中回答了OP的问题。你应该发表你的回答作为答案,以便他可以接受他们,我们可以对他们进行投票。 –

回答

1

标准UIProgressView只显示一个进度,如果您尝试捕获多个项目的进度,则将具有层次结构为Progress/NSProgress的对象。例如。如果上传五个文件,则有五个Progress对象,每个上传对象一个,然后有第六个NSProgress,其中UIProgressView观察,其他五个作为孩子。请参阅NSProgress class reference中创建进展树对象。一个例子见https://stackoverflow.com/a/36616538/1271826

如果您想要一个视觉上代表个人进度的进度视图,您必须自己做(或找到一个能够做到这一点的第三方控件)。但标准UIProgressView不会为你做这个。

但这并不难。例如,您可以创建水平堆栈视图,为每个想要跟踪的NSProgress添加一个UIProgressView,将子视图的相应宽度设置为例如它们代表整个任务的百分比。

例如这里有三个UIProgressView安排子视图水平堆叠视图:

enter image description here

话虽如此,我更喜欢标准单一,整合的UIProgessView因为用户可以更容易地看到多远沿着他们。如果你有这样的一系列进度观点,很难直观地看到“我有多长时间”,因为你必须查看所有单独的进度视图,并从心理上找出它(例如“第一个看起来像是50完成了%,第二个完成了66%,第三个完成了75%......所以整个事情到底有多远?!?)。

无论如何,在这里我的Swift代码来呈现上述。我知道你正在寻找的Objective-C,但希望这足以说明,可以很容易地在任何斯威夫特或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") 
    } 
}