【发布时间】:2020-01-10 19:43:37
【问题描述】:
尝试在 SwiftUI 中实现登录屏幕。基于其他类似的问题,我将采用在主 ContentView 中使用 Observable EnvironmentObject 和 ViewBuilder 的方法,它会对此做出反应并显示适当的屏幕。
但是,即使属性按照预期更新,预览中的视图也不会更改。在模拟器中构建和运行时一切正常,但在预览中永远不会发生更改。
以下是将代码简化为单个文件中可能的最小示例(仅缺少在 SceneDelegate 中传递环境对象,这不会影响预览)。
import SwiftUI
import Combine
struct ContentView: View {
@EnvironmentObject var userAuth: UserAuth
@ViewBuilder
var body: some View {
if !userAuth.person.isLoggedin {
FirstView()
} else {
SecondView()
} }
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(UserAuth())
}
}
struct Person {
var isLoggedin: Bool
init() {
self.isLoggedin = false
}
}
class UserAuth: ObservableObject {
@Published var person: Person
init(){
self.person = Person()
}
let didChange = PassthroughSubject<UserAuth,Never>()
// required to conform to protocol 'ObservableObject'
let willChange = PassthroughSubject<UserAuth,Never>()
func login() {
// login request... on success:
willChange.send(self)
self.person.isLoggedin = true
didChange.send(self)
}
}
struct SecondView: View {
var body: some View {
Text("Second View!")
}
}
struct SecondView_Previews: PreviewProvider {
static var previews: some View {
SecondView().environmentObject(UserAuth())
}
}
struct FirstView: View {
@EnvironmentObject var userAuth: UserAuth
var body: some View {
VStack {
Button(action: {
self.userAuth.login()
}) {
Text("Login")
}
Text("Logged in: " + String(self.userAuth.person.isLoggedin))
}
}
}
struct FirstView_Previews: PreviewProvider {
static var previews: some View {
FirstView().environmentObject(UserAuth())
}
}
编辑:根据下面的答案,我已将环境对象添加到内部视图中,但不幸的是,在预览模式下视图仍然没有改变。
【问题讨论】:
-
它就在那里——你可以在
Debug Preview中看到它进入了SecondView分支,所以这只是一个预览刷新问题。我会忽略这一点。 -
@Asperi 问题是在我的真实应用程序中,视图位于单独的文件中,因此在查看 ContentView 时,如果预览不打算刷新,它对于调试登录功能毫无用处。