swiftui - How to pass the value of progress in SwiftUI(maybe with combine)?
问题描述
I just started to learn SwiftUI, but did not have time to Combine. I don’t understand much about this. How to pass a value to the progress of downloading in ProgressView. how to configure ODRManager and how to transfer the value when downloading is in progress, not 0 and immediately 1, but 0.0 ... 0.1.0.2 ... 0.8,0.9,1.0 I would like to know different ways and means only SwiftUI, and using Combine or other methods.
Thanks a lot .
SwiftUI Code
import SwiftUI
struct ProgressView: View {
@Binding var value: Float
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .leading) {
Rectangle()
.frame(width: geometry.size.width, height: geometry.size.height)
.opacity(0.3)
.foregroundColor(.gray)
Rectangle()
.frame(width: min(CGFloat(self.value) * geometry.size.width, geometry.size.width), height: geometry.size.height)
.foregroundColor(.blue)
.animation(.linear)
}.cornerRadius(45.0)
}
}
}
struct ContentView: View {
@State var progressValue: Float = 0.0
var body: some View {
VStack {
Button(action: { //here is the function to download from ondemand }) {
Text("Download")
.padding(.init(top: 10, leading: 30, bottom: 10, trailing: 30))
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(14)
}
.padding(.bottom, 30)
ProgressView(value: $progressValue)
.environmentObject(self.manager)
.frame(width: 250, height: 20)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
OnDemand manager code
class ODRManager: NSObject {
var resourceRequest : NSBundleResourceRequest?
var progress:Float = 0.0
func fetchODRResourceWithName(fileName: String) {
guard self.resourceRequest == nil else {return}
self.resourceRequest = NSBundleResourceRequest(tags: [fileName])
progress = Float((resourceRequest?.progress.fractionCompleted)!)
self.resourceRequest!.progress.addObserver(self, forKeyPath: "fractionCompleted", options: .new, context: nil)
self.resourceRequest?.conditionallyBeginAccessingResources(completionHandler: { (resourceAvailable) in
if !resourceAvailable {
self.resourceRequest!.beginAccessingResources { err in
guard err == nil else {
print(err as Any)
return
}
print("downloading..")
}
} else {
print("was downloaded")
}
})
}
func stopDownloadingFile() {
guard self.resourceRequest != nil else {
return
}
self.resourceRequest!.endAccessingResources()
self.resourceRequest!.progress.removeObserver(self, forKeyPath: "fractionCompleted")
self.resourceRequest!.progress.cancel()
self.resourceRequest = nil
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "fractionCompleted" {
DispatchQueue.main.async { [weak self] in
self.progress = Float((self?.resourceRequest!.progress.fractionCompleted)!)
}
}
}
}
解决方案
目前尚不清楚 和 之间的关系ODRManager
,ContentView
但我建议在它们之间引入一些中间模型(以避免紧密耦合),例如
class ProgressItem: ObservableObject {
@Published var progressValue: Float = .zero
}
所以将相同的实例传递ProgressItem
给
class ODRManager: NSObject {
var resourceRequest : NSBundleResourceRequest?
var progress: ProgressItem? = nil // set up in init
...
和
struct ContentView: View {
@ObservedObject var progress = ProgressItem() // as variant
...
ProgressView(value: $progress.progressValue)
.frame(width: 250, height: 20)
您只能有条件地加入引擎和 UI,而无需相互依赖。
推荐阅读
- javascript - Dom 元素无限递增
- javascript - 满足第一个条件时执行 else 块
- docker - 如何使用 env 文件将环境变量传递到独立的 vscode 远程容器中?
- mysql - 为什么 INSERT ... ON DUPLICATE KEY UPDATE 影响行报告 2?
- javascript - 后缺少名称。操作员
- python - 迭代字典的最佳方式(性能方面)
- vba - MS Access 获取更新的行 ID 或拦截更新
- javascript - 在 JavaScript 中修改时,某些单选按钮不会保持选中状态
- hana - 在 Azure SQL 数据仓库中虚拟化 SAP HANA 表
- javascript - css 或 js 文件的文件大小限制