繁体   English   中英

SwiftUI @State 变量不改变视图

[英]SwiftUI @State variable does not change view

使用 HalfASheet ( https://github.com/franklynw/HalfASheet )。

我有一个名为ProjectsView的视图,在ProjectsViewZStack中,我有ProjectSortingSortingView (都注入了EnvironmentObject )。 我希望ProjectSorting中的Text () 被更改,并且SortingView中的HStack () 具有复选标记,两者都取决于SortingValuessorting变量的值。 用户可以通过按下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
        }
    }
}

您的SortingViewProjectSorting都访问类型为 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM