【问题标题】:SwiftUI onTapGesture does not work with ObservedObject in Mac appSwiftUI onTapGesture 不适用于 Mac 应用程序中的 ObservedObject
【发布时间】:2019-08-04 16:03:40
【问题描述】:

我想根据另一个视图 (LeftView) 中的点击手势操作来更新视图 (RightView)。下面是我完成此操作的示例代码:

AppState.swift

import Foundation

class AppState: ObservableObject {
    @Published var tapCount: Int = 0

    func incrementTapCount() {
        self.tapCount += 1
        print("tap count \(self.tapCount)")
    }
}

LeftView.swift

import SwiftUI

struct LeftView: View {
    @ObservedObject var appState = AppState()

    var body: some View {
        VStack {
            Text("Left View")
        }
        .frame(width: 100, height: 200)
        .onTapGesture {
            print("tapped left view")
            self.appState.incrementTapCount()
        }
    }
}

RightView.swift

import SwiftUI

struct RightView: View {
    @ObservedObject var appState = AppState()

    var body: some View {
        VStack {
            Text("Right View")
            Text("Tap Count: \(self.appState.tapCount)")
        }.frame(width: 200, height: 200)
    }
}

ContentView.swift

import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack {
            LeftView()
            RightView()
        }.frame(width: 300, height: 200)
    }
}

很遗憾,RightView 文本不会随着点击次数而更新。但是,如果我在 ObservableObject 类中使用计时器来更新点击次数,那么 RightView 会正确更新。

import Foundation

class AppState: ObservableObject {
    @Published var tapCount: Int = 0

    init() {
        Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
            self.tapCount += 1
        }
    }

    func incrementTapCount() {
        self.tapCount += 1
        print("tap count \(self.tapCount)")
    }
}

为什么 LeftView 中的点击手势不更新 RightView 文本?

【问题讨论】:

    标签: swift macos swiftui


    【解决方案1】:

    LeftViewRightView 都在初始化各自独立的 AppState 对象,因此它们观察到的状态不同。

    在您的两个视图中,将@ObservedObject 保留为未初始化的属性:

    LeftView.swift & RightView.swift

    @ObservedObject var appState: AppState
    

    当您在 SwiftUI 视图中有这样一个未初始化的属性时,您需要在想要使用该视图的任何时候为其提供一个值。

    PreviewProvider 使用您的视图实例,因此 Xcode 可以在画布上向您显示它,并且它只需要您为 appState 提供一个 占位符 值。该值并不重要(除了 Xcode 画布外,它不会在任何地方使用),因此您只需要提供正确类型的内容:

    #if DEBUG
    struct LeftView_Previews: PreviewProvider {
        static var previews: some View {
            LeftView(appState: AppState())
        }
    }
    #endif
    

    最后,在ContentView 中,您需要将对单个共享 AppState 的引用传递给LeftViewRightView,这样他们就可以分别观察同一个对象: p>

    ContentView.swift

    import SwiftUI
    
    struct ContentView: View {
        var sharedAppState = AppState()
    
        var body: some View {
            HStack {
                LeftView(appState: sharedAppState)
                RightView(appState: sharedAppState)
            }.frame(width: 300, height: 200)
        }
    }
    

    现在两个视图都在观察 AppState 的同一个实例,当其属性发生变化时它们都会更新。

    您也可以使用@EnvironmentObject 在应用中的所有视图之间共享状态,但由于我们在这里只关心两个视图@ObservedObject 是一个务实的选择。

    【讨论】:

    • 很好,我完全错过了 AppState 初始化问题。您能否还显示对 LeftView 和 RightView 的 PreviewProvider 代码所需的更改?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 2014-05-15
    • 1970-01-01
    • 2022-10-02
    • 2019-12-18
    相关资源
    最近更新 更多