Как передать значение прогресса в SwiftUI (может быть, с комбайном)? - PullRequest
0 голосов
/ 24 февраля 2020

Я только начал изучать SwiftUI, но не успел Объединить. Я не очень понимаю об этом. Как передать значение прогрессу загрузки в ProgressView. как настроить ODRManager и как передать значение во время загрузки, а не 0 и сразу 1, а 0,0 ... 0,1,0,2 ... 0,8,0,9,1,0. Я хотел бы знать различные способы и средства только SwiftUI, и используя Combine или другие методы.

Большое спасибо.

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

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)!)
            }
        }
    }
}

Ответы [ 2 ]

1 голос
/ 24 февраля 2020

Не ясно, как в настоящее время соотносятся 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)

вы можете присоединиться к движку и пользовательскому интерфейсу только условно, без зависимости друг от друга.

1 голос
/ 24 февраля 2020
class ODRManager: ObservableObject {
    var resourceRequest : NSBundleResourceRequest?
    @Published var progress:Float = 0.0 

    ... rest of code as before ...
}

теперь вы можете использовать его как любой другой ObservableObject в любом из SwiftUI.View

...