SwiftUI - navigationBarBackButtonHidden - 是否可以禁用滑动返回手势?

38

如果我设置一个自定义返回按钮(每个人都想要,隐藏丑陋的文本;-)),并使用.navigationBarBackButtonHidden,导航控制器上的标准滑动返回手势将不起作用。有没有办法恢复这个功能并使用自定义的返回按钮?

例如:

NavigationView {
    NavigationLink(destination: DummyViewer())
     {
       Text("Go to next view"
    } 
 }
struct DummyViewer: View {
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    var body: some View {
        Text("Hello, World!").navigationBarBackButtonHidden(true)
            .navigationBarItems(leading:
                Button(action: { self.presentationMode.wrappedValue.dismiss()}) {
                    Text("Custom go back")
                }
        )
    }
}

如果我这样做,我将无法向后滑动到先前的视图,似乎手势随之被禁用了...该如何恢复它呢?

如果我这样做,我将无法向后滑动到先前的视图,似乎手势随之被禁用了...该如何恢复它呢?


1
这个回答解决了你的问题吗?在SwiftUI中隐藏导航栏而不失去滑动返回手势 - iSpain17
7个回答

103

我发现关于创建自定义NavigationView的内容都无法正常工作,但是我发现通过扩展UINavigationController可以实现自定义返回按钮和滑动返回手势。

extension UINavigationController: UIGestureRecognizerDelegate {
    override open func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    }
}

2
仍然可以在iOS 14.2上运行。多么强大的咒语! - Shengchalover
仍然在14.5中有效,谢谢!我想知道这意味着什么,因为这将全局应用于所有导航控件。 - TruMan1
适用于iOS 15开发者测试版1。 - liudasbar
2
这太棒了。 - Kyle Beard
1
但是用户返回后如何进行一些清理工作? - Tony Chen
显示剩余7条评论

25

我希望能整合 Nick Bellucci 给出的答案,使代码也能在其他情况下工作,例如当 NavigationView 的子视图是 ScrollView 或正在监听拖动手势的 View 时。

extension UINavigationController: UIGestureRecognizerDelegate {
    override open func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    } 

    // To make it works also with ScrollView
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        true
    }
}

使其与滚动视图一起工作的好提示。 - ZYiOS
我应该把它放在哪里?我无法在iOS15上使其工作。 - tcgumus
1
@tcgumus 您可以将此放置在项目中的任何 Swift 文件中。 - Niccolò Fontana
这个完美地运作了,因为我的整个视图是一个页面样式的tabview。需要进行一些微调,但它工作了。谢谢! - darkstar

4

我刚刚创建了一个方法,它不会动画显示但可以正常工作。


extension View {
    func onBackSwipe(perform action: @escaping () -> Void) -> some View {
        gesture(
            DragGesture()
                .onEnded({ value in
                    if value.startLocation.x < 50 && value.translation.width > 80 {
                        action()
                    }
                })
        )
    }
}

用法

struct TestView: View {
    @Environment (\.presentationMode) var mode
    var body: some View {
        VStack {
            Color.red
        }
        .onBackSwipe {
            mode.wrappedValue.dismiss()
        }
    }

}

对我来说,适用于16.4版本。非常感谢。 - undefined

2
我想集成Niccolò Fontana提供的答案,他又整合了Nick Bellucci的答案,以使代码更加完善。
Niccolò Fontana还使其在NavigationView的子视图为ScrollView或正在侦听拖动手势的View时也能正常工作。
但在这种情况下,您将同时滚动和滑动。那很烦人。如果您想要原始行为,则应使用该片段:
extension UINavigationController: UIGestureRecognizerDelegate {
    override open func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    } 

    // To make it works also with ScrollView
    // public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    //     true
    // }

    // To make it works also with ScrollView but not simultaneously 
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        true
    }

}

1
你可能只需要在你的代码中添加这个,然后就可以轻松地使用自定义的返回按钮或隐藏导航栏来实现滑动返回手势。
extension UINavigationController {
    override open func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = nil
    }
}

-1

您可以将标题设置为空的字符串。这样返回按钮的标题就会为空:

struct ContentView: View {

    var body: some View {

        NavigationView {

            NavigationLink(destination: Text("Here you are")) {

                Text("Next").navigationBarTitle("")
            }
        }
    }
}

如果需要,您可以在onAppearonDisappear中设置标题。


嗨,我添加了更多信息。它涉及到后退按钮和滑动手势是否会触发的问题。 - sTOOs

-2
如果仍然需要,在这里我回答了如何设置自定义返回按钮并保存滑动返回手势。

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