SwiftUI onTapGesture不适用于Mac app中的ObservedObject

时间:2019-08-04 16:03:40

标签: swift macos swiftui

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

AppState.swift

g

LeftView.swift

  layer_id.slice(0, layer_id.lastIndexOf("-")) // take the part till the last -
  // or, depending on the exact usecase
  layer_id.slice(0, layer_id.indexOf("-", layer_id.indexOf("-"))) // take the string till the second -
  // or
  layer_id.match(/(\d+-\d+)/)[0] // take the first part that matches two groups of one or more chars seperated by a -
  // or
  layer_id.slice(0, 5) // take only the first 5 chars

RightView.swift

import Foundation

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

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

ContentView.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文本不会随着点击数更新。但是,如果我在ObservableObject类中使用计时器来更新拍数,则RightView会正确更新。

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

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

1 个答案:

答案 0 :(得分:2)

LeftViewRightView都分别初始化各自的AppState对象,因此它们不会观察相同的状态。

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

LeftView.swift和RightView.swift

@ObservedObject var appState: AppState

在SwiftUI视图中具有这样的未初始化属性时,您需要在每次使用视图时为其提供一个值。

PreviewProvider使用视图的一个实例,因此Xcode可以在画布上向您显示它,并且只需要您为appState提供一个 placeholder 值。该值并不是很重要(除了Xcode画布,它没有在其他任何地方使用),因此您只需要提供正确类型的值即可:

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

最后在ContentView中,您需要将对单个共享 AppState的引用向下传递到LeftViewRightView,以便他们可以每个观察到相同的对象:

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是务实的选择