首页 > 解决方案 > 如何从另一个类更改@Binding var?

问题描述

我有一个视图,它以这种方式包含在 SwiftUI 中的另一个视图中:

第一个视图

struct CircularProgressBar: View {

    @Binding var circleProgress: CGFloat

    var widthAndHeight: CGFloat
    var labelSize: CGFloat?
    var staticColor: Color?
    var progressColor: Color
    var showLabel: Bool?
    var lineWidth: CGFloat?

    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Circle()
                    .stroke(self.staticColor ?? Color.gray, lineWidth: self.lineWidth ?? 15)
                    .frame(width: geometry.size.width, height: geometry.size.height)
                Circle()
                    .trim(from: 0.0, to: self.circleProgress)
                    .stroke(self.progressColor, lineWidth: self.lineWidth ?? 15)
                    .frame(width: geometry.size.width, height: geometry.size.width)
                    .rotationEffect(Angle(degrees: -90))
                if self.showLabel ?? true {
                    Text("\(Int(self.circleProgress*100))%")
                        .frame(width: geometry.size.width, height: geometry.size.height)
                        .font(.custom("HelveticaNeue", size: self.labelSize ?? 20.0))
                }
            }
        }
            .frame(width: widthAndHeight, height: widthAndHeight)
    }

}

第二视图:

struct ContentView: View {
    @ObservedObject var simulator:Simulator
    @State var progress: CGFloat
    var body: some View {
        HStack(alignment: .center) {
            VStack(alignment: .leading) {
                Text(simulator.getName())
                Text("Version: "+simulator.getVersion())
                Spacer()
                Image("logo")
                    .resizable()
                    .frame(width: 50, height: 40)
            }.padding()

            VStack(alignment: .center) {
                Text("State")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)

                CircularProgressBar(circleProgress: $progress, widthAndHeight: 180, labelSize: 30, progressColor: .blue)


                Button(action: {
                    withAnimation{self.updateCircleProg()}
                    //Action here
                }) {
                    Text("Show Logs")
                }.frame(maxWidth: .infinity, maxHeight: .infinity)
            }
        }
    }
    func updateCircleProg(){
        self.progress = CGFloat(Float.random(in: 0 ..< 1))
    }
}

我能够从模拟器 Object 上的另一个类更新 UI,因为它被声明为ObservableObject并且其属性为@Published

我能够改变progress第二视图的内部。

我的问题是:是否可以progress从另一个类更改包含在第二视图中的第一视图并更新 UI?(超出第二个视图)?

我尝试更改它,但 UI 没有更新,这就是我所做的:

class AppDelegate: NSObject, NSApplicationDelegate {

    var window: NSWindow!
    var simulator : Simulator!
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        simulator = Simulator(name: "simulator", version: "1")
        let contentView = ContentView(simulator: simulator, progress: 0.0)
        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { 
            self.simulator.setName(name: "Big Simulator")
            self.simulator.setVersion(version: "2")
            contentView.progress = 0.3
        }
        window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
            styleMask: [.titled, .miniaturizable, .fullSizeContentView],
            backing: .buffered, defer: false)
        window.center()
        window.setFrameAutosaveName("Main Window")
        window.contentView = NSHostingView(rootView: contentView)
        window.makeKeyAndOrderFront(nil)

    }

标签: swiftswiftui

解决方案


好吧,SwiftUI 以不同的方式工作......所以你需要

class Simulator: ObservableObject {
   @Published var progress: CGFloat = .zero // << and here

所以更新

DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { 
    self.simulator.setName(name: "Big Simulator")
    self.simulator.setVersion(version: "2")
    self.simulator.progress = 0.3    // << modifier here or anywhere
}

VStack(alignment: .center) {
    Text("State")
        .frame(maxWidth: .infinity, maxHeight: .infinity)

    // observe here
    CircularProgressBar(circleProgress: self.$simulator.progress, widthAndHeight: 180, labelSize: 30, progressColor: .blue)

注意: @State设计为在内部视图中使用,因此遵循此规则很容易养成为 state 属性赋予private的习惯,始终如此。


推荐阅读