SwiftUI 以编程方式从可表示返回到视图

Posted

技术标签:

【中文标题】SwiftUI 以编程方式从可表示返回到视图【英文标题】:SwiftUI go back programmatically from representable to View 【发布时间】:2019-10-16 18:10:47 【问题描述】:

我正在尝试在新的 swift ui 应用中设置二维码阅读器。

我可以用这一行加载 UIKit qr 阅读器视图

NavigationLink(destination: QRCodeScan())Text("Scan QR")

这是我的 ViewControllerRepresentable

struct QRCodeScan: UIViewControllerRepresentable 

func makeCoordinator() -> Coordinator 
    Coordinator(self)


func makeUIViewController(context: Context) -> ScannerViewController 
    let vc = ScannerViewController()
    vc.delegate = context.coordinator
    return vc


func updateUIViewController(_ vc: ScannerViewController, context: Context) 


class Coordinator: NSObject, QRCodeScannerDelegate 
    func codeDidFind(_ code: String) 
        print(code)
        //Go back to the last page, take 'code' with you
    

    var parent: QRCodeScan

    init(_ parent: QRCodeScan) 
        self.parent = parent
    

在“返回最后一页...”这一行,我需要以编程方式返回将用户发送到二维码扫描仪的页面。页面加载了导航返回按钮,我非常需要复制此按钮行为以在需要时调用

任何帮助/指针表示赞赏

tia

【问题讨论】:

【参考方案1】:
struct ContentView: View 
    @State var isActive = false
    @State var code = ""
    var body: some View 
        NavigationView 
            ZStack 
                NavigationLink(destination: DetailView(isActive: $isActive, code: $code), isActive: $isActive, label:  EmptyView() )
                Button(action: 
                    self.isActive.toggle()
                , label: 
                    Text("navigate")
                )
            
        
    

struct DetailView: View 

    @Binding var isActive: Bool
    @Binding var code: String

    var body: some View 
        Button(action: 
            self.code = "new code"
            self.isActive.toggle()
        ) 
            Text("Back")
        
    

这可能对你有帮助,使用 NavigationLink 的 isActive 参数来回导航

【讨论】:

我相信上面的这种方法是首选的方法。现有的 SwiftUI API 通常通过绑定到 isVisible(例如警报)来工作,并通过在关闭时将其设置为 false 来解除它。另一方面,通过 presentation 进行操作现在似乎很普遍,但在我看来,它似乎偏离了 SwiftUI 的声明式风格。 是的,我阅读这个答案的方式并没有真正解决我的问题,它仍然在屏幕 2 上添加了一个按钮,用户必须按下才能返回,这不是什么我一直在寻找,我已经有一个按钮,我需要一种在事件处理程序中调用此操作的方法 @robbo5899 在“//回到最后一页,随身携带'code'”添加self.code = "new code" self.isActive.toggle(),我只是用一个按钮来告诉你它是如何工作的 啊,好的,谢谢,使用 Representable 并从协调器中获取数据似乎有点尴尬,非常感谢【参考方案2】:

简短的回答是你现在不能这样做。既没有绑定也没有设置环境值可以触发它。我的猜测是会有某种类似于presentationMode 的环境值,你可以利用它,但它目前没有被宣传。

您可以尝试当前的presentationMode,但我真正的建议是将您的 QR 扫描仪呈现为一张纸而不是推送。无论如何,从导航的角度来看,这实际上可能更有意义。为此,请在您的演示者中设置一个 @State var 以在其出现时进行处理。

@State var presentQRScanner = false

var body: some View 
    Button("Scan") 
        self.presentQRScanner = true
    
    .sheet(isPresented: $presentQRScanner)  QRCodeScan() 

然后,当您想以编程方式关闭时,您的 UIViewControllerRepresentable:

@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

func scannedCode() 
    presentationMode.wrappedValue.dismiss()

或者,您也可以通过在 QRCodeScan 上创建一个由代码调用的闭包来驱动演示者,然后让演示者解散。

var onCodeScanned: (Code) -> Void =  _ in 

func scannedCode() 
    onCodeScanned(code)

在演示者中:

var body: some View 
    Button("Scan") 
        self.presentQRScanner = true
    
    .sheet(isPresented: $presentQRScanner)  
        QRCodeScan(onCodeScanned:  
            self.process($0)
            self.presentQRScanner = false
        )
    

编辑:不知道isActive 绑定,如果您仍想将视图推送到导航堆栈而不是显示它,那么它实际上应该对您有用。

【讨论】:

谢谢,采纳了您的建议并更改了视图的呈现方式,现在需要从模态视图中取回“代码”。【参考方案3】:

您可以使用NavigationLink 的以下重载来做到这一点。它从 ios 13 及更高版本开始可用。

这是代码。

注意将$isShowingView 绑定传递给NavigationLink 对象和您想要通过按钮点击出去的ChildView

struct ContentView: View 
    
    @State var isShowingChildView = false
    
    var body: some View 
        NavigationView 
            NavigationLink(isActive: $isShowingChildView) 
                ChildView(isShowingView: $isShowingChildView)
             label: 
                Text("Open new view")
            
        
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    

struct ChildView: View 
        
    @Binding
    var isShowingView: Bool
    
    var body: some View 
        VStack 
            Button("Back to parent view") 
                isShowingView = false
            
        
    

【讨论】:

以上是关于SwiftUI 以编程方式从可表示返回到视图的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式从 SwiftUI 列表中删除行并刷新列表视图?

以编程方式一个接一个地关闭 SwiftUI 视图不起作用

如何以编程方式创建等效的 SwiftUI 堆栈视图分隔符

如何以编程方式在 SwiftUI 中滚动?

在 iOS 13 上以编程方式滚动 SwiftUI ScrollView

将 SwiftUI 视图渲染到屏幕外并将视图另存为 UIImage 以共享