如何在 SwiftUI 中传递进度值(可能与 combine)?
How to pass the value of progress in SwiftUI(maybe with combine)?
刚开始学SwiftUI,还没来得及Combine。我对此了解不多。
ProgressView中下载进度如何传值。
如何配置ODRManager以及如何在下载过程中传输值,不是0立即1,而是0.0 ... 0.1.0.2 ... 0.8,0.9,1.0
我想知道不同的方式和方法只有 SwiftUI,以及使用 Combine 或其他方法。
非常感谢。
SwiftUI 代码
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 经理代码
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)!)
}
}
}
}
class ODRManager: ObservableObject {
var resourceRequest : NSBundleResourceRequest?
@Published var progress:Float = 0.0
... rest of code as before ...
}
现在您可以将它用作 SwiftUI.View
中的任何其他 ObservableObject
目前尚不清楚 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 有条件地 w/o 相互依赖。
刚开始学SwiftUI,还没来得及Combine。我对此了解不多。 ProgressView中下载进度如何传值。 如何配置ODRManager以及如何在下载过程中传输值,不是0立即1,而是0.0 ... 0.1.0.2 ... 0.8,0.9,1.0 我想知道不同的方式和方法只有 SwiftUI,以及使用 Combine 或其他方法。
非常感谢。
SwiftUI 代码
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 经理代码
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)!)
}
}
}
}
class ODRManager: ObservableObject {
var resourceRequest : NSBundleResourceRequest?
@Published var progress:Float = 0.0
... rest of code as before ...
}
现在您可以将它用作 SwiftUI.View
中的任何其他 ObservableObject目前尚不清楚 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 有条件地 w/o 相互依赖。