首页 > 解决方案 > 在子视图中更新 EnvironmentObject 会导致视图弹出

问题描述

我有一个更新 EnvironmentObject 的子视图,然后导致子视图弹回其父视图。我正在创建一个使用本教程中类似“喜欢”功能的应用程序:https ://www.hackingwithswift.com/books/ios-swiftui/letting-the-user-mark-favorites

每次单击赞按钮并更新 EnvironmentObject 赞对象时,视图都会弹出到前一个 (ProductGridView) 视图,而不是停留在子视图 (ProductDetailView) 上。

struct ContentView: View {
@State private var tabSelection = 0
@ObservedObject var products = Products()
@ObservedObject var favorites = Favorites()

var body: some View {
    VStack {
        TabView(selection: $tabSelection) {
            NavigationView{
                ProductGridView()
            }
            .tabItem { Image(systemName: "megaphone")
                Text("Products")
            }.tag(0)
             .environmentObject(products)
             .environmentObject(favorites)
     }


struct ProductGridView: View {
var columns: [GridItem] = Array(repeating: .init(.flexible()), count: 2)
@EnvironmentObject var products: Products
@EnvironmentObject var favorites: Favorites
var body: some View {
    VStack{
            ScrollView(.vertical,  showsIndicators: false) {
                LazyVGrid(columns: columns, alignment: .leading, spacing: 20) {
                        ForEach(products.products, content: {
                            product in
                            NavigationLink(destination: ProductDetailView(product: product)) {
                                ProductCellView(product: product)
                                    .padding(.horizontal, 10)
                            }
                        })
                    }
                }.onAppear() {
                    self.products.fetchData()
                }
            }

struct ProductDetailView: View {
    let product: Product
    @EnvironmentObject var favorites: Favorites
    var body: some View {
        ScrollView(showsIndicators: false) {
            VStack{
                ProductImageView(product: product)
                        Button(action: {
                            if favorites.contains(product) {
                                favorites.remove(product) //Updating here causes issue
                            } else {
                                favorites.add(product) //Updating here causes issue
                            }
                        }) {
                            if favorites.contains(product){
                                Image(systemName: "heart.fill")
                            }
                            else{
                                Image(systemName: "heart")
                            }
                        }
                    }

class Favorite : Identifiable, Encodable {
    var id = UUID()
    var name: String
...

class Favorites: ObservableObject {
    @Published private var products: [String]?
...

struct Product: Identifiable{
    let id = UUID()
    let productname: String
...

标签: iosswiftswiftui

解决方案


看起来您的 fetch data 调用可能会导致问题。

struct YourContentView: View {
    @State private var tabSelection = 0
    @ObservedObject var products = Products()
    @ObservedObject var favorites = Favorites()
    
    var body: some View {
        VStack {
            TabView(selection: $tabSelection) {
                NavigationView{
                    ProductGridView()
                }
                .tabItem { Image(systemName: "megaphone")
                    Text("Products")
                }.tag(0)
                .environmentObject(products)
                .environmentObject(favorites)
            }
        }
    }
    
}

struct ProductDetailView: View {
    let product: Product
    @EnvironmentObject var favorites: Favorites
    
    var body: some View {
        ScrollView(showsIndicators: false) {
            VStack{
                Image(systemName: "photo")
                    .resizable()
                    .scaledToFit()
                
                Button {
                    if favorites.products?.contains(product) ?? false {
                        favorites.remove(product) //Updating here causes issue
                    } else {
                        favorites.add(product) //Updating here causes issue
                    }
                } label: {
                    if favorites.products?.contains(product) ?? false{
                        Image(systemName: "heart.fill")
                    }
                    else{
                        Image(systemName: "heart")
                    }
                }
            }
        }
    }
}

struct ProductCellView: View {
    @State var product: Product
    
    var body: some View {
        HStack {
            Image(systemName: "photo")
            Text(product.productname)
        }
    }
}


struct ProductGridView: View {
    let columns: [GridItem] = Array(repeating: .init(.flexible()), count: 2)
    @EnvironmentObject var products: Products
    @EnvironmentObject var favorites: Favorites

    var body: some View {
        VStack{
            ScrollView(.vertical,  showsIndicators: false) {
                LazyVGrid(columns: columns, alignment: .leading, spacing: 20) {
                    ForEach(products.products, content: {
                        product in
                      
                        NavigationLink(destination: ProductDetailView(product: product)) {
                            ProductCellView(product: product)
                                .padding(.horizontal, 10)
                        }
                    })
                }
            }.onAppear() {
                self.products.fetchData()
            }
        }
    }
}

class Favorites: ObservableObject {
    @Published var products: [Product]? = []
  
    init() {}
    
    func remove(_ product: Product) {
        products?.removeAll(where: { $0.id == product.id })
    }
    
    func add(_ product: Product) {
        products?.append(product)
    }
}

class Products: ObservableObject, Identifiable {
    @Published var products: [Product]
    
    init() {
        products = [.init(productname: "ApplePie"), .init( productname: "Cheeseburger")]
    }
   
    func fetchData() {
//        uncommenting this code will cause product grid view to reload because it relies on products
//        products = [.init(productname: "ApplePie"), .init( productname: "Cheeseburger")]
    }
}



struct Product: Identifiable, Equatable {
    let id = UUID()
    let productname: String

    public static func ==(lhs: Product, rhs: Product) -> Bool {
        lhs.id == rhs.id
    }
}

推荐阅读