尝试在SwiftUI中实现登录屏幕。基于其他类似的问题,我打算采用在主ContentView中使用Observable EnvironmentObject和ViewBuilder的方法,它会对此做出反应并显示适当的屏幕。
但是,即使该属性正在按预期更新,该视图也不会在Preview中更改。在模拟器中构建和运行时,一切工作正常,但是在预览中,更改永远不会发生。
下面是将代码简化为单个文件中最小的示例的示例(只是缺少在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())
}
}
编辑:基于以下答案,我已将环境对象添加到内部视图中,但不幸的是,该视图在“预览”模式下仍未更改。
答案 0 :(得分:2)
struct FirstView_Previews: PreviewProvider {
static var previews: some View {
FirstView().environmentObject(UserAuth())
}
}
环境对象也必须在PreviewProvider中设置
答案 1 :(得分:1)
struct ContentView: View {
@ObservedObject var userAuth = UserAuth () // @ObservedObject
var body: some View {
NavigationView{ // Navigation
}.environmentObject(UserAuth) //.environmentObject
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(UserAuth())
}
}
struct SecondView: View {
@EnvironmentObject var userAuth: UserAuth // only EnvironmentObject
var body: some View {
Text("Second View!")
}
}
struct SecondView_Previews: PreviewProvider {
static var previews: some View {
SecondView().environmentObject(UserAuth())
}
}
答案 2 :(得分:0)
Canvas 不提供预览的问题是我的 ObservableObject
正在读取用户默认值
@Published var fName: String = Foundation.UserDefaults.standard.string(forKey: "fName") !
{ didSet {
Foundation.UserDefaults.standard.set(self.fName, forKey: "fName")
}
}
所以可以在模拟器和设备上使用,但没有 Canvas 预览。我尝试了很多方法来提供预览数据,因为预览无法从 UserDefaults
(不是设备)读取,并意识到如果 UserDefault 不存在,我可以输入初始/默认值:
@Published var fName: String = Foundation.UserDefaults.standard.string(forKey: "fName") ?? "Sean"
{ didSet {
Foundation.UserDefaults.standard.set(self.fName, forKey: "fName")
}
}
现在预览/画布显示我的视图,我可以继续使用我的可观察对象进行编码。目的是在 Observable 对象中放入一些要使用的默认代码。