禁用 SwiftUI NavigationLink 的滑动返回功能

15

我该如何在SwiftUI中禁用向后滑动手势?子视图只能通过返回按钮来退出。

7个回答

16

隐藏导航栏中的返回按钮后,滑动返回手势将被禁用。您可以使用.navigationBarItems()来设置自定义返回按钮。

struct ContentView: View {
    var body: some View {
        NavigationView{
            List{
                NavigationLink(destination: Text("You can swipe back")){
                    Text("Child 1")
                }
                NavigationLink(destination: ChildView()){
                    Text("Child 2")
                }
            }
        }
    }
}

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

    var body:some View{
        Text("You cannot swipe back")
            .navigationBarBackButtonHidden(true)
            .navigationBarItems(leading: Button("Back"){self.presentationMode.wrappedValue.dismiss()})
    }
}


2
这个方法可以运行,但至少会失去后退按钮的本地化(即国际化),这可能是你关心的,也可能不是。 - SirVer
5
有没有一种方法可以隐藏返回按钮而不失去滑动返回的功能? - bze12
@SirVer,在您的“返回”按钮中使用本地化字符串应该没问题吧?如果您关心国际化,那应该不难。 - Rillieux
您还会失去“后退”按钮的智能功能,该功能仅在标题不适合时才显示图标。 - bio

6

对我而言,添加此扩展程序是有效的(禁用了全局返回手势,以及另一种禁用手势识别器的方法):

extension UINavigationController: UIGestureRecognizerDelegate {
    override open func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }
    
    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { 
        return false
    }
}

4

只有完全删除手势识别器才对我有效。
我将其封装成一个单一的修改器(添加到详细视图)。

struct ContentView: View {
    
    var body: some View {
        VStack {
            ...
        )
        .disableSwipeBack()
    }
}

DisableSwipeBack.swift

import Foundation
import SwiftUI

extension View {
    func disableSwipeBack() -> some View {
        self.background(
            DisableSwipeBackView()
        )
    }
}

struct DisableSwipeBackView: UIViewControllerRepresentable {
    
    typealias UIViewControllerType = DisableSwipeBackViewController
    
    
    func makeUIViewController(context: Context) -> UIViewControllerType {
        UIViewControllerType()
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
    }
}

class DisableSwipeBackViewController: UIViewController {
    
    override func didMove(toParent parent: UIViewController?) {
        super.didMove(toParent: parent)
        if let parent = parent?.parent,
           let navigationController = parent.navigationController,
           let interactivePopGestureRecognizer = navigationController.interactivePopGestureRecognizer {
            navigationController.view.removeGestureRecognizer(interactivePopGestureRecognizer)
        }
    }
}

你可以使用 SwiftUI 层级中的 UIViewControllerRepresentable,然后访问其父视图的父视图,无需使用第三方库即可解决导航控制器问题。

2023年以后不起作用 - undefined

4

我使用Introspect库,然后只需执行以下操作:

import SwiftUI
import Introspect

struct ContentView: View {
   var body: some View {
      Text("A view that cannot be swiped back")
           .introspectNavigationController { navigationController in
              navigationController.interactivePopGestureRecognizer?.isEnabled = false
      }
   }
}

3

navigationBarBackButtonHidden设置为true会失去美丽的动画效果,当你设置了navigationTitle时。

所以我尝试了另一个答案。

navigationController.interactivePopGestureRecognizer?.isEnabled = false

但这对我没有用。
尝试以下代码后,它可以正常工作。
NavigationLink(destination: CustomView()).introspectNavigationController {navController in
            navController.view.gestureRecognizers = []
        }

preview


1
这应该被标记为正确答案。其他的答案会导致你失去美丽的iOS动画,正如你所说的。 - Vitor
1
那么,你正在使用SwiftUI Introspect库? - surfrider

2

这个答案展示了如何在SwiftUI中配置你的导航控制器(简而言之,使用UIViewControllerRepresentable来访问UINavigationController)。而这个答案则展示了如何禁用滑动手势。将它们结合起来,我们可以做到以下操作:

Text("Hello")
  .background(NavigationConfigurator { nc in
     nc.interactivePopGestureRecognizer?.isEnabled = false
  })

这样你就可以继续使用内置的返回按钮功能。

1
以下更多地复制了现有的iOS chevron图像。 对于被接受的答案。 也就是用图像chevron替换"back"
 .navigationBarItems(leading: Button("Back"){self.presentationMode.wrappedValue.dismiss()})

使用

Button(action: {self.presentationMode.wrappedValue.dismiss()}){Image(systemName: "chevron.left").foregroundColor(Color.blue).font(Font.system(size:23, design: .serif)).padding(.leading,-6)}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接