[英]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.