[英]SwiftUI @State variable does not change view
使用 HalfASheet ( https://github.com/franklynw/HalfASheet )。
我有一个名为ProjectsView
的视图,在ProjectsView
的ZStack
中,我有ProjectSorting
和SortingView
(都注入了EnvironmentObject
)。 我希望ProjectSorting
中的Text
() 被更改,并且SortingView
中的HStack
() 具有复选标记,两者都取决于SortingValues
中sorting
变量的值。 用户可以通过按下SortingView
中的Button
来更改sorting
的值。
无论出于何种原因, ProjectSorting
中的Text
() 根本没有改变。 而 SortingView 中的HStack
() 仅在其ancestor stack
具有另一个包含来自环境的SortingView
@State variable from the environment
Text
() 时才获得复选标记,我觉得这很奇怪。
我应该改变什么? 有什么办法可以使用@EnvironmentObject
来完成这项工作吗? 我是新手,不能真正理解其他包装器,所以我想在@State
、 @Binding
、 @EnvirionmentObject
中完成这项工作。 提前致谢。
SortingValues.swift
import Combine
class SortingValues: ObservableObject {
@Published var sorting = "Top Rated"
}
ProjectsView.swift
struct ProjectsView: View {
@Binding var isPresented: Bool
@State var showSortingSheet = false
var body: some View {
ZStack {
NavigationView {
VStack(spacing: 0) {
ProjectsTopView(isPresented: $isPresented)
ProjectSorting(showSortingSheet: $showSortingSheet)
.environmentObject(SortingValues())
ProjectList()
}
.navigationBarHidden(true)
}
SortingView(showSortingSheet: $showSortingSheet)
.environmentObject(SortingValues())
}
}
}
ProjectSorting.swift
import SwiftUI
struct ProjectSorting: View {
@EnvironmentObject var sortingValues: SortingValues
@Binding var showSortingSheet: Bool
@State var sortingValue = ""
var body: some View {
VStack {
HStack {
Text("Projects")
Spacer()
Button {
showSortingSheet.toggle()
} label: {
HStack(spacing: 3) {
Image("sortingArrows")
Text(sortingValue) // < 🟩 this is the Text I want to be changed
}
}
}
// Another HStack goes here
}
.onReceive(sortingValues.$sorting) { sorting in
print("This is ProjectSorting. sorting:", sorting) // < this does not print when I close the half sheet
sortingValue = sorting
}
}
}
SortingView.swift
import SwiftUI
import HalfASheet
struct SortingView: View {
@EnvironmentObject var sortingValues: SortingValues
@Binding var showSortingSheet: Bool
@State var sortingValue = ""
var body: some View {
VStack {
HalfASheet(isPresented: $showSortingSheet) {
let sorting = ["Most Recent", "Most Reviewed", "Top Rated", "Lowest Price", "Highest Price"]
VStack(alignment: .leading) {
ForEach(sorting, id: \.self) { sorting in
VStack(alignment: .leading, spacing: 14) {
Button (action: {
sortingValues.sorting = sorting
}, label: {
HStack { // 🟦
Text(sorting)
Spacer()
if sorting == sortingValue { // < this is where I add the checkmark
Image(systemName: "checkmark")
}
}
.foregroundColor(.primary)
})
if sorting != "Highest Price" {
Divider()
}
}
}
}
}
.height(.fixed(325))
// Text("Inside VStack, outside HalfASheet") // adding this Text DOES NOT make the HStack have a checkmark
Text("Inside VStack, outside HalfASheet: \(sortingValue)") // 🟨 adding this Text DOES make the HStack have a checkmark
}
.onReceive(sortingValues.$sorting) { sorting in
// the two printing lines below print correctly every time I tap the Button
print("This is SortingView. sorting:", sorting)
print("sortingValues.sorting: \(sortingValues.sorting)")
sortingValue = sorting
}
}
}
您的SortingView
和ProjectSorting
都访问类型为 SortingValues 的环境SortingValues
,但您正在向每个环境传递新的单独实例。 因此,您在一个地方所做的更改不会反映在另一个地方,因为每个视图都在与同一类型的两个完全不同的对象之一进行通信。
如果您希望它们与同一个 object 实例进行交互,您需要在 object 层次结构中位于两者之上的点声明它,并确保将单个实例传递给两者。 例如:
struct ProjectsView: View {
@Binding var isPresented: Bool
@State var showSortingSheet = false
@StateObject var sortingValues = SortingValues()
var body: some View {
ZStack {
NavigationView {
VStack(spacing: 0) {
ProjectsTopView(isPresented: $isPresented)
ProjectSorting(showSortingSheet: $showSortingSheet)
.environmentObject(sortingValue)
ProjectList()
}
.navigationBarHidden(true)
}
SortingView(showSortingSheet: $showSortingSheet)
.environmentObject(sortingValues)
}
}
}
但你可以 go 更进一步。 因为环境对象和值会自动向下传播到视图层次结构中,所以您可以将两个单独.environmentObject
调用替换为一个:
struct ProjectsView: View {
@Binding var isPresented: Bool
@State var showSortingSheet = false
@StateObject var sortingValues = SortingValues()
var body: some View {
ZStack {
NavigationView {
VStack(spacing: 0) {
ProjectsTopView(isPresented: $isPresented)
ProjectSorting(showSortingSheet: $showSortingSheet)
ProjectList()
}
.navigationBarHidden(true)
}
SortingView(showSortingSheet: $showSortingSheet)
}
.environmentObject(sortingValues)
}
}
可能有更好的方法来处理对您观察到的 model 中的变化做出反应,而不是在本地 state 变量中复制变量值——但确保您的所有视图都使用相同的共享环境 object 应该让您上路。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.