1

当在 MenuView 中按下按钮时,我在让 ContentBodyView 正确更新时遇到问题。

当我打印出@Published currentPage 变量时,它会在按下按钮时发生变化,但似乎不会进入 ContentBodyView。我错过了什么吗?

我根据本教程编写了代码:https ://blckbirds.com/post/how-to-navigate-between-views-in-swiftui-by-using-an-environmentobject/

我尝试在 ContentBodyView 上执行 .onReceive 事件,但视图仍然没有改变。

应用程序.swift:

@main
struct App: App {
    
    @StateObject var viewRouter = ViewRouter()
    
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(viewRouter)
        }
    }
}

内容视图:

struct ContentView: View {
    // MARK: - PROPERTIES
    
    // for future use...
    @State var width = UIScreen.main.bounds.width - 90
    // to hide view...
    @State var x = -UIScreen.main.bounds.width + 90
    
    @EnvironmentObject var viewRouter: ViewRouter
    
    // MARK: - BODY
    var body: some View {

            
        VStack {
            ZStack(alignment: Alignment(horizontal: .leading, vertical: .top)) {

                ContentBodyView(x: $x)
                    .environmentObject(ViewRouter())
                
                MenuView(x: $x)
                    .shadow(color: Color.black.opacity(x != 0 ? 0.1 : 0), radius: 5, x: 5, y: 0)
                    .offset(x: x)
                    .background(Color.black.opacity(x == 0 ? 0.5 : 0).ignoresSafeArea(.all, edges: .vertical).onTapGesture {
                        // hiding the view when back is pressed...
                        withAnimation {
                            x = -width
                        }
                    }) //: background
                    .environmentObject(ViewRouter())
            } //: ZSTACK
            
            // adding gesture or drag feature...
            .gesture(DragGesture().onChanged({ (value) in
                withAnimation {
                    if value.translation.width > 0 {
                        // disabling over drag...
                        if x < 0 {
                            x = -width + value.translation.width
                        }
                    } else {
                        if x != -width {
                            x = value.translation.width
                        }
                    }
                }
            }).onEnded({ (value) in
                withAnimation {
                    // checking if half the value of menu is dragged means setting x to 0...
                    if -x < width / 2 {
                        x = 0
                    } else {
                        x = -width
                    }
                }
            })) //: GESTURE 
        } //: VSTACK
    }
}

菜单视图:

struct MenuView: View {
    // MARK: - PROPERTIES
    
    var edges = UIApplication.shared.windows.first?.safeAreaInsets
    
    // for future use...
    @State var width = UIScreen.main.bounds.width - 90
    // to hide view...
    @Binding var x: CGFloat
    
    @EnvironmentObject var viewRouter: ViewRouter
    
    // MARK: - BODY
    
    var body: some View {
        HStack(spacing: 0) {
            VStack(alignment: .leading) {
                
                HStack{
                    
                    Button(action: {
                        withAnimation {
                            x = -width
                        }
                    }) {
                        Image(systemName: "xmark")
                            .resizable()
                            .frame(width: 18, height: 18)
                            .padding()
                            .padding(.top, 25)
                            .foregroundColor(Color.black)
                    }
                    
                    Spacer()
                }
                
                ForEach(menuData) { item in
                    Button(action: {
                        withAnimation {
                            if (item.router == "shareables") {
                                viewRouter.currentPage = .shareables
                            } else {
                                viewRouter.currentPage = .home
                            }
                            x = -width
                        }
                    }) {
                        Text("\(item.label)")
                    } //: BUTTON
                } //: FOREACH
                
            } //: VSTACK
            .padding(.horizontal,20)
            // since vertical edges are ignored....
            .padding(.top,edges!.top == 0 ? 15 : edges?.top)
            .padding(.bottom,edges!.bottom == 0 ? 15 : edges?.bottom)
            // default width...
            .frame(width: UIScreen.main.bounds.width - 90)
            .background(Color.white)
            .ignoresSafeArea(.all, edges: .vertical)
            
            Spacer(minLength: 0)
        } //: HSTACK
    }
}

内容体视图:

struct ContentBodyView: View {
    // MARK: - PROPERTIES
    
    @EnvironmentObject var viewRouter: ViewRouter
    
    @Binding var x : CGFloat
    
    // MARK: - BODY
    var body: some View{
        
        VStack {
            switch viewRouter.currentPage {
                case .home:
                    NavigationBarView(x: $x, title: "Home")
                    Spacer()
                    HomeView()
                        .transition(.scale)
                case .shareables:
                    NavigationBarView(x: $x, title: "Shareables")
                    Spacer()
                    ShareablesView()
                        .transition(.scale)
            } //: SWITCH
           
        } //: VSTACK
        // for drag gesture...
        .contentShape(Rectangle())
        .background(Color.white)

    }
}

视图路由器:

final class ViewRouter: ObservableObject {
    @Published var currentPage: Page = .home
}

enum Page {
    case home
    case shareables
}
4

1 回答 1

2

ViewRouter尝试在所有视图中使用相同的实例。

以下代码创建 的新实例ViewRouter

ContentBodyView(x: $x)
                .environmentObject(ViewRouter())

MenuView(x: $x)
                ...
                .environmentObject(ViewRouter())

将它们替换为:

@EnvironmentObject var viewRouter: ViewRouter

...

.environmentObject(viewRouter)

但实际上,每个环境通常只需要注入.environmentObject一次,因此所有这些调用可能都是不必要的。

注入ViewRouter一次ContentView就足够了(如果您不使用sheet等):

@StateObject var viewRouter = ViewRouter()

...

ContentView().environmentObject(viewRouter)
于 2020-12-15T16:40:21.457 回答