SwiftUI-如何关闭工作表视图,同时关闭该视图

时间:2020-02-20 05:27:30

标签: ios swift navigation swiftui dismiss

我想实现该功能。就像来自Apple的“查找”视图一样。

我的目的是当图纸视图通过导航推入另一个视图时,用户可以点击导航项目按钮以关闭图纸视图。像这样,下面的gif。

enter image description here

我尝试实现此功能。

我发现了一个问题,当用户点击“完成”按钮时。该应用程序不会关闭工作表视图。它仅将视图弹出到父视图。像这样,下面的gif。

enter image description here

这是我的代码。

import SwiftUI

struct ContentView: View {
    @State var isShowSheet = false
    var body: some View {
        Button(action: {
            self.isShowSheet.toggle()
        }) {
            Text("Tap to show the sheet")
        }.sheet(isPresented: $isShowSheet) {
            NavView()
        }
    }
}

struct NavView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: NavSubView()) {
                Text("Enter Sub View")
            }
        } .navigationViewStyle(StackNavigationViewStyle())
    }
}

struct NavSubView: View {
    @Environment(\.presentationMode) var presentationMode

    var body: some View {
        Text("Hello")
        .navigationBarItems(trailing:
            Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }){
                Text("Done")
            }
        )
    }
}

我如何实现此功能? :) 请帮助我,谢谢。 :)

2 个答案:

答案 0 :(得分:7)

由于工作表中的导航可能足够长并且关闭可能无法在所有导航子视图中进行,因此我更喜欢使用环境具有仅在所需位置指定关闭功能的功能,而不是通过所有导航堆栈传递绑定。

这是可行的方法(已通过Xcode 11.2 / iOS 13.2测试)

1)定义环境键以存储图纸状态

----------------------------------------
System information
----------------------------------------
Platform:    Windows-10-10.0.16299-SP0
Python:      3.8.1
NumPy:       1.18.1
OpenCV:      4.2.0
----------------------------------------

2)将此环境值设置为工作表内容的根,因此在声明时它将在任何子视图中可用

struct ShowingSheetKey: EnvironmentKey {
    static let defaultValue: Binding<Bool>? = nil
}

extension EnvironmentValues {
    var showingSheet: Binding<Bool>? {
        get { self[ShowingSheetKey.self] }
        set { self[ShowingSheetKey.self] = newValue }
    }
}

3)仅在要使用的子视图中声明和使用环境值

    }.sheet(isPresented: $isShowSheet) {
        NavView()
           .environment(\.showingSheet, self.$isShowSheet)
    }

答案 1 :(得分:6)

我从未尝试过SwiftUI,但是我来自UIKit + RxSwift,所以我有点知道绑定是如何工作的。我从SwiftUI教程中阅读了很多示例代码,而您消除模式的方式实际上是正确的,但显然不适用于导航堆栈。

我刚刚学习的一种方法是使用@Binding变量。这可能不是最佳解决方案,但它确实有效!

因此,您的$isShowSheet中有这个ContentView。通过在该NavView中声明一个变量,将该对象传递给您的NavView结构。

ContentView

    .....

    }.sheet(isPresented: $isShowSheet) {
        NavView(isShowSheet: self.$isShowSheet)
    }

NavView

struct NavView: View {
    @Binding var isShowSheet: Bool

    var body: some View {
        NavigationView {
            NavigationLink(destination: NavSubView(isShowSheet: self.$isShowSheet)) {
                Text("Enter Sub View")
            }
        } .navigationViewStyle(StackNavigationViewStyle())
    }
}

最后,对您的subView做同样的事情。

NavSubView

struct NavSubView: View {
    @Environment(\.presentationMode) var presentationMode

    @Binding var isShowSheet: Bool

    var body: some View {
        Text("Hello")
        .navigationBarItems(trailing:
            Button(action: {
                //self.presentationMode.projectedValue.wrappedValue.dismiss()
                self.isShowSheet = false
            }){
                Text("Done")
            }
        )
    }
}

现在您可以看到,您只需要向该绑定变量isShowSheet-false发送一个新信号即可。

self.isShowSheet = false

Voila!

enter image description here