在 SwiftUI 中隐藏导航栏而不会丢失向后滑动手势

Ngu*_*Hào 14 swift swiftui

在 SwiftUI 中,每当导航栏被隐藏时,滑动返回手势也会被禁用。

有什么办法可以在保留 SwiftUI 中的向后滑动手势的同时隐藏导航栏?我已经有一个自定义的“返回”按钮,但仍然需要手势。

我已经看到了一些 UIKit 的解决方案,但仍然不知道如何在 SwiftUI 中做到这一点

这是您自己尝试的代码:

import SwiftUI

struct RootView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: SecondView()) {
                Text("Go to second view")
            }
        }
    }
}

struct SecondView: View {
    var body: some View{
        Text("As you can see, swipe to go back will not work")
        .navigationBarTitle("")
        .navigationBarHidden(true)
    }
}
Run Code Online (Sandbox Code Playgroud)

非常感谢任何建议或解决方案

Nic*_*cci 50

这应该通过扩展UINavigationController.

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

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    }
}
Run Code Online (Sandbox Code Playgroud)

  • iOS 17 中存在一个错误,如果您使用此解决方案滑回根目录,您的视图将会出现故障并冻结。我不知道这个问题的解决办法。 (10认同)
  • 谢谢。我已经寻找了几个小时,您的解决方案是唯一可以使用精确的滑动手势的解决方案。请介意解释一下这是什么意思:`viewControllers.count > 1`?再次感谢你 (2认同)
  • @MerunasGrincalaitis 只是检查以确保导航堆栈具有多个视图控制器。本质上,如果在 rootviewcontroller 上,手势应该返回 false。 (2认同)

sha*_*zar 10

适应@Nick Bellucci 解决方案,但不适用于所有屏幕,

创建一个AppState类

class AppState {
    static let shared = AppState()

    var swipeEnabled = false
}
Run Code Online (Sandbox Code Playgroud)

添加昵称的扩展名(已修改)

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

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if AppState.shared.swipeEnabled {
            return viewControllers.count > 1
        }
        return false
    }
    
}
Run Code Online (Sandbox Code Playgroud)

和你的看法

struct YourSwiftUIView: View {
    var body: some View {
        VStack {
            // your code
        }
        .onAppear {
            AppState.shared.swipeEnabled = false
        }
        .onDisappear {
            AppState.shared.swipeEnabled = true
        }
    }
    
}
Run Code Online (Sandbox Code Playgroud)

  • 我一直在寻找这样的东西,很好的方法 (2认同)

小智 7

使用 UINavigationController 扩展时,您可能会遇到一个错误,该错误会在您开始滑动屏幕后阻止导航并让其离开而不返回导航。添加.navigationViewStyle(StackNavigationViewStyle())到 NavigationView 确实解决了这个问题。

如果您需要基于设备的不同视图样式,此扩展程序有助于:

extension View {
    public func currentDeviceNavigationViewStyle() -> AnyView {
        if UIDevice.current.userInterfaceIdiom == .pad {
            return AnyView(self.navigationViewStyle(DefaultNavigationViewStyle()))
        } else {
            return AnyView(self.navigationViewStyle(StackNavigationViewStyle()))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Fab*_*b1n 7

这比尼克贝鲁奇的回答更容易。这是最简单的工作解决方案:

extension UINavigationController {
    override open func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = nil
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果我处于根视图并向后滑动,屏幕会冻结。有人有同样的问题吗? (3认同)

小智 6

黑客在全局隐藏导航栏而不丢失 SwiftUI 中的向后滑动手势。它适用于 iOS 14 - 17。

import UIKit

extension UINavigationController {
    open override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        navigationBar.isHidden = true
    }
}
Run Code Online (Sandbox Code Playgroud)