在这种情况下,我有一个BaseView
包含一些常见元素,一个BaseViewModel
包含一些常见功能,但是当其@Published
var得到更新时,没有BaseView
刷新发生。
设置是这样的:
class BaseViewModel: ObservableObject {
@Published var overlayView: AnyView = EmptyView().convertToAnyView()
func forceViewRefresh() {
self.objectWillChange.send()
}
func setOverlayView(overlayView: AnyView) {
self.overlayView = overlayView
}
}
此视图模型子类为BaseViewModel
:
class FirstViewModel: BaseViewModel {
func showOverlayView() {
self.setOverlayView(overlayView: OverlayView().convertToAnyView())
}
}
我还有一个BaseView
,我在其中使用overlayView
struct BaseView<Content: View>: View {
let content: Content
@ObservedObject var viewModel = BaseViewModel()
init(content: () -> Content) {
self.content = content()
}
var body: some View {
ZStack {
Color.green.edgesIgnoringSafeArea(.vertical)
content
viewModel.overlayView
}
}
}
显示的第一个视图是FirstView
,它符合BaseViewProtocol
,并且具有扩展FirstViewModel
的{{1}}。
BaseViewModel
}
单击struct FirstView: BaseViewProtocol {
@ObservedObject var viewModel = FirstViewModel()
var body: some View {
BaseView() {
Button("Show overlay") {
viewModel.showOverlayView()
}
}
}
中的Show overlay
按钮将调用First View
上的showOverlayView()
函数,该功能继而调用FirstViewModel
上的setOverlayView
。 BaseViewModel
中overlayView
的值按预期变化,但未调用BaseViewModel
上的视图刷新。
我在做什么错了?
非常感谢。
答案 0 :(得分:0)
我刚刚测试了此代码示例,并且可以在Xcode 12 beta 6和iOS 14 beta 8上正常工作
struct ContentView: View {
@StateObject private var viewModel = FirstViewModel()
var body: some View {
ZStack {
Button(action: { viewModel.showOverlayView() }) {
Text("Press")
}
viewModel.overlayView
}
}
}
class BaseViewModel: ObservableObject {
@Published var overlayView: AnyView = AnyView(EmptyView())
func forceViewRefresh() {
self.objectWillChange.send()
}
func setOverlayView(overlayView: AnyView) {
self.overlayView = overlayView
}
}
class FirstViewModel: BaseViewModel {
func showOverlayView() {
self.setOverlayView(
overlayView: AnyView(
Color.blue
.opacity(0.2)
.allowsHitTesting(false)
)
)
}
}
答案 1 :(得分:0)
通常在SwiftUI中,您不会在body
之外创建视图。视图创建应该留给SwiftUI-相反,您可以定义一些其他控件来告诉SwiftUI 如何和何时创建视图。
这是一个简化的演示,如何为不同的视图显示不同的叠加层。
您可以创建基本的OverlayView:
enum OverlayType {
case overlay1, overlay2
}
struct OverlayView: View {
let overlayType: OverlayType
@ViewBuilder
var body: some View {
if overlayType == .overlay1 {
Text("Overlay1") // can be replaced with any view you want
}
if overlayType == .overlay2 {
Text("Overlay1")
}
}
}
并在您的BaseView中使用它(如果overlayType
是nil
,则不会显示叠加层)
struct BaseView<Content>: View where Content: View {
let overlayType: OverlayType?
let content: () -> Content
var body: some View {
ZStack {
Color.green.edgesIgnoringSafeArea(.vertical)
content()
if overlayType != nil {
OverlayView(overlayType: overlayType!)
}
}
}
}
现在在ContentView中,您可以使用BaseView并指定其OverlayType。
struct ContentView: View {
@State var overlayType: OverlayType?
var body: some View {
BaseView(overlayType: overlayType) {
Button("Show overlay") {
overlayType = .overlay1
}
}
}
}
一些注意事项:
为简单起见,我使用了@State
变量来控制叠加层。如果您的ViewModel还有其他用例,则可能需要将逻辑移到那里。
请注意,最好使用AnyView
代替@ViewBuilder
。
此外,如果您想在视图内观察ObservableObject
,则需要使用@ObservedObject
,而不是@ObservableObject
。