【问题标题】:Dismissing a View using a "static nav bar"使用“静态导航栏”关闭视图
【发布时间】:2020-05-11 22:35:02
【问题描述】:

我创建了一个简单的视图作为导航栏,其中包含一个菜单按钮和一些文本。我将其用作NavigationView 之外的顶级元素,这使我可以在所有进入视图的子页面中保持静态视图。我尝试不使用带有导航栏项目的默认导航栏的原因是为了避免在切换视图时伴随淡出动画而出现的解雇/创建。

我现在面临的问题是当我离开父视图时关闭子视图。我可以将按钮从菜单图标更新为后退图标,但不会触发按钮的操作。一直在网上寻找是否有人做过类似的事情但没有运气,我不确定我想要实现的目标是否可能,或者我是否以正确的方式去做。即使在根视图中初始化了标头,是否仍然可以从子视图调用self.presentationMode.wrappedValue.dismiss()?任何帮助表示赞赏,这是我到目前为止所拥有的:

根视图(View1):

struct View1: View {
    @State var showMenuButton: Bool = false
    var body: some View {
        VStack {
            CustomNavigationView(showMenuButton: self.showMenuButton)

            NavigationView {
                NavigationLink(destination: View2()) {
                    Text("View 2")
                }
                .navigationBarTitle("")
                .navigationBarHidden(true)
                .onDisappear(){
                    self.showMenuButton = false
                }
                .onAppear() {
                    self.showMenuButton = true
                }
            }
        }
    }
}

根视图的子视图(View2):

struct View2: View {
    var body: some View {
        VStack{
            Text("This is View 2")
            .navigationBarTitle("")
            .navigationBarHidden(true)
            NavigationLink(destination: View3()) {
                Text("View 3")
            }
        }
    }
}

视图 2 (View3) 的子视图:

struct View3: View {
    var body: some View {
        VStack{
            Text("This is View 3")
            .navigationBarTitle("")
            .navigationBarHidden(true)
        }
    }
}

自定义导航视图:

struct CustomNavigationView: View {
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    var showMenuButton = false
    var body: some View {
        VStack {
            HStack {
                if showMenuButton {
                    Button(action: {
                        //Do Something
                    }) {
                        Image(systemName: "line.horizontal.3")
                        .foregroundColor(.black)
                    }
                } else {
                    Button(action: { self.presentationMode.wrappedValue.dismiss()}) {
                        Image(systemName: "arrow.left")
                        .foregroundColor(.black)
                    }
                }
                Text("Sometext")            
            }
        }
    }
}

【问题讨论】:

    标签: ios swift swiftui swiftui-navigationlink


    【解决方案1】:

    您在第一个视图中使用的环境对象“presentationMode”无法关闭您推送的视图。每个想要被摒弃的观点都必须有自己的对象。第一个视图内的对象不属于任何其他推送的视图。因此,您需要创建视图模型来管理此任务。

    这是示例代码。希望能帮助您解决问题。

    class NavigationObserver: ObservableObject {
        private var views: [Int:Binding<PresentationMode>] = [:]
        private var current: Int = 0
    
        func popView() {
           guard let view = views[current] else {
              return
           }
           view.wrappedValue.dismiss()
           views[current] = nil
           current -= 1
         }
    
        func pushView(id: Int, newView: Binding<PresentationMode>) {
           guard views[id] == nil else {
              return
           }
           current += 1
           views[id] = newView
         }
       }
    
    struct ContentView: View {
    @State var showMenuButton: Bool = false
    @ObservedObject var observer = NavigationObserver()
    var body: some View {
        VStack {
            CustomNavigationView(observer: self.observer, showMenuButton: self.showMenuButton)
    
            NavigationView {
                NavigationLink(destination: View2(observer: self.observer)) {
                    Text("View 2")
                }
                .navigationBarTitle("")
                .navigationBarHidden(true)
                .onDisappear(){
                    self.showMenuButton = false
                }
                .onAppear() {
                    self.showMenuButton = true
                }
            }
        }
    }}
    struct View2: View {
    @Environment(\.presentationMode) var presentationMode
    @ObservedObject var observer: NavigationObserver
    var body: some View {
        VStack{
            Text("This is View 2")
            .navigationBarTitle("")
            .navigationBarHidden(true)
            NavigationLink(destination: View3(observer: self.observer)) {
                Text("View 3")
            }
        }.onAppear {
            self.observer.pushView(id: 1, newView: self.presentationMode)
        }
    }}
    
    struct View3: View {
    @Environment(\.presentationMode) var presentationMode
    @ObservedObject var observer: NavigationObserver
    var body: some View {
        VStack{
            Text("This is View 3")
            .navigationBarTitle("")
            .navigationBarHidden(true)
        }.onAppear
            {
                self.observer.pushView(id: 2, newView: self.presentationMode)
            }
    }
    }
    
    struct CustomNavigationView: View {
    @ObservedObject var observer: NavigationObserver
    var showMenuButton = false
    var body: some View {
        VStack {
            HStack {
                if showMenuButton {
                    Button(action: {
                        //Do Something
                    }) {
                        Image(systemName: "line.horizontal.3")
                        .foregroundColor(.black)
                    }
                } else {
                    Button(action: {
                        self.observer.popView()
                    }) {
                        Image(systemName: "arrow.left")
                        .foregroundColor(.black)
                    }
                }
                Text("Sometext")
            }
        }
    }
    }
    

    谢谢,X_X

    【讨论】:

    • 完美!完全按照我的想象工作。我知道presentationMode 对象无法关闭子视图,这就是我碰壁的地方。据我了解,您正在创建一个字典,其中导航历史记录中每个视图的 id 作为键,单个视图presentationMode 作为值。然后将其解散并从字典中删除。非常感谢!
    猜你喜欢
    • 2011-03-19
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-24
    • 2017-08-20
    • 1970-01-01
    相关资源
    最近更新 更多