如何在 SwiftUI 中从一个视图更新另一个视图

How to update one view from within another in SwiftUI

我正在处理一个 SwiftUI 视图,我在其中填充了主视图中的其他子视图。我的问题是如何从子视图中调用主视图中的内容?

这是我的主视图的代码:

struct MovieList: View {
    
    @ObservedObject var viewModel = MovieViewModel()
    
    var body: some View {
        VStack {
            
            ScrollView(.vertical) {
                VStack {
                    ForEach(self.viewModel.movie) { movie in
                        MovieView(movie: movie)
                    }
                }
            }
            
        }
        .navigationBarTitle("Movies")
        .onAppear {
            self.viewModel.fetchMovies() // Fetch all movies and cause entire view to refresh and populate movies
        }
    }
}

此主视图通过添加多个 MovieView 实例来填充电影列表。

这是 MovieView 的一些示例代码:

struct MovieView: View {
    
      
    let movie: Movie
    
    var body: some View {
        VStack(alignment: .leading) {
            
            HStack {
                Text(“Movie Title: \(movie.title)”)
            }.padding([.top, .leading, .bottom])
            
              
           Button("Do not show this movie") {
            // Update user prefers to hide the movie.
            // But also somehow from within here call viewModel.fetchMovies() in the other view to refresh the movies list
      }


        }
    }
}

因此,例如,在其中一个 MovieView 视图中,如何调用主视图中的 fetchMovies() 以便更新所有内容?

本质上是一个项目列表被填充,我希望其中任何一个能够刷新/在整个主视图上执行一些操作

就更新 Movie 本身而言,正如评论中所指出的,您可能希望将 Binding 传递给它。查看 ForEach.

的更改

就再次调用 fetchMovies 而言,您可以将整个 ObservableObject 传递给子视图,或者只传递对您需要的函数的引用(如下所示):

struct Movie : Identifiable {
    var id = UUID()
    var title : String
    var isHidden: Bool
}

class MovieViewModel : ObservableObject {
    @Published var movies = [Movie]()
    
    func fetchMovies() {
        //fetch
    }
}

struct MovieList: View {
    @ObservedObject var viewModel = MovieViewModel()
    
    var body: some View {
        VStack {
            ScrollView(.vertical) {
                VStack {
                    ForEach($viewModel.movies) { $movie in
                        MovieView(movie: $movie, fetchMovies: viewModel.fetchMovies)
                    }
                }
            }
        }
        .navigationBarTitle("Movies")
        .onAppear {
            self.viewModel.fetchMovies()
        }
    }
}

struct MovieView: View {
    @Binding var movie: Movie
    var fetchMovies : () -> Void
    
    var body: some View {
        VStack(alignment: .leading) {
            
            HStack {
                Text("Movie Title: \(movie.title)")
            }.padding([.top, .leading, .bottom])
            
            
            Button("Do not show this movie") {
                movie.isHidden = true
                fetchMovies()
            }
        }
    }
}