![](/img/trans.png)
[英]Calling functions in init() of SwiftUI View and ObservableObject
[英]SwiftUI: Init ObservableObject based on Environment
在此示例中,蓝色矩形最初应在 .regular 大小 class 的设备上可见,而在.regular
大小 class 的设备上.compact
隐藏。
我正在使用一个名为Settings
的ObservableObject
和@Published
变量isVisible
来管理矩形的可见性。 我的问题是我不知道如何从ContentView
使用正确的horizontalSizeClass
ntalSizeClass 初始化Settings
。 现在我正在使用.onAppear
来更改isVisible
的值,但这会触发.onReceive
。 在紧凑型设备上,这会导致矩形在视图呈现时可见并淡出,而不是立即不可见。
如何根据 Horizo horizontalSizeClass
等环境值初始化Settings
,以便isVisible
从一开始就正确?
struct ContentView: View {
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@StateObject var settings = Settings()
@State var opacity: CGFloat = 1
var body: some View {
VStack {
Button("Toggle Visibility") {
settings.isVisible.toggle()
}
.onReceive(settings.$isVisible) { _ in
withAnimation(.linear(duration: 2.0)) {
opacity = settings.isVisible ? 1 : 0
}
}
Rectangle()
.frame(width: 100, height: 100)
.foregroundColor(.blue)
.opacity(opacity)
}
.onAppear {
settings.isVisible = horizontalSizeClass == .regular // too late
}
}
}
class Settings: ObservableObject {
@Published var isVisible: Bool = true // can't get size class here
}
矩形在开始时不应该是可见的:
withAnimation
应该在更改 state 的按钮操作上完成,例如
import SwiftUI
struct RectangleTestView: View {
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@State var settings = Settings()
var body: some View {
VStack {
Button("Toggle Visibility") {
withAnimation(.linear(duration: 2.0)) {
settings.isVisible.toggle()
}
}
Rectangle()
.frame(width: 100, height: 100)
.foregroundColor(.blue)
.opacity(settings.opacity)
}
.onAppear {
settings.isVisible = horizontalSizeClass == .regular
}
}
}
struct Settings {
var isVisible: Bool = true
var opacity: CGFloat {
isVisible ? 1 : 0
}
}
仅供参考,我们不再使用onReceive
,因为他们添加了onChange
。 最好将视图数据保留在结构中,而不是将其移动到昂贵的对象中。 “视图非常便宜,我们鼓励您将它们作为主要封装机制” SwiftUI WWDC 2020 中的 Data Essentials 20:50。
我们只需要执行依赖注入(已知环境是父环境,因此可以很容易地注入子环境),并且使用内部视图很简单,例如
struct ContentView: View {
@Environment(\.horizontalSizeClass) var horizontalSizeClass
struct MainView: View {
// later knonw injection
@EnvironmentObject var settings: Settings
var body: some View {
VStack {
Button("Toggle Visibility") {
settings.isVisible.toggle()
}
Rectangle()
.frame(width: 100, height: 100)
.foregroundColor(.blue)
.opacity(settings.isVisible ? 1 : 0) // << direct dependency !!
}
.animation(.linear(duration: 2.0), value: settings.isVisible) // << explicit animation
}
}
var body: some View {
MainView() // << internal view
.environmentObject(
Settings(isVisible: horizontalSizeClass == .regular) // << initial injecttion !!
)
}
}
使用 Xcode 13.4 / iOS 15.5 测试
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.