根据预览中的Observable更新SwiftUI View

时间:2020-01-10 19:43:37

标签: xcode swiftui

尝试在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())
    }
}

编辑:基于以下答案,我已将环境对象添加到内部视图中,但不幸的是,该视图在“预览”模式下仍未更改。

3 个答案:

答案 0 :(得分:2)

struct FirstView_Previews: PreviewProvider {
    static var previews: some View {
        FirstView().environmentObject(UserAuth())
    }
}

环境对象也必须在PreviewProvider中设置

更新 enter image description here

答案 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 对象中放入一些要使用的默认代码。