如何修复破坏 iOS 17 中 SwiftUI 导航的 UINavigationController 扩展

问题描述 投票:0回答:1

我在 iOS 15 和 iOS 16 中一直使用以下扩展,似乎没有任何问题。对于上下文,我在项目中实现了此功能,以提供保留向后滑动手势的功能,以便在视图层次结构(子级到父级)中向后导航。这是因为使用后退按钮的自定义实现(用于 UI 样式目的)隐藏 SwiftUI 中的工具栏或导航栏会导致向后滑动手势丢失。

这就是这个扩展发挥作用的地方。感谢尼克·贝鲁奇的最高评价答案,我在这里找到了这一点。 在 SwiftUI 中隐藏导航栏而不丢失向后滑动手势

现在的问题是,当从子视图滑回后返回根视图时,根视图在 iOS 17.0 中在设备和模拟器上都会冻结并中断。有没有人重现或遇到过这个问题?要完全重新创建场景,只需在子视图上使用

.toolbar(.hidden)
,或改为
.navigationBarBackButtonHidden()

还需要注意的是,我正在使用

dismiss()
来点击弹出的视图。下面的片段...您只需根据自己的喜好将自定义后退按钮放置在子视图中即可重新创建此示例。

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

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    }
}
struct CustomBackButton: View {
    @Environment(\.dismiss) var dismiss
    var body: some View {
        Button(action: {
            dismiss()
        }) {
            // your pretty swiftui code here
        }
    }
}

编辑:我可能已经陷入了“圆孔中的方钉”的境地。解决方案很可能是利用现有的导航栏并覆盖后退按钮设计,同时提出隐藏导航栏的方法。这里需要注意的是,它可能会以意想不到的方式在顶部边缘填充内容,因此内容上可能需要一些自定义的填充或边距,当导航栏从视图中隐藏时,这些内容会与导航栏的填充发生冲突。

swift swiftui navigation gesture ios17
1个回答
0
投票

我使用的是 iOS 17,没有遇到任何问题

根视图冻结并中断

下面是我的一些代码。

struct ContentView: View {
    @StateObject private var navigationStack = CustomNavigationStack()

    var body: some View {
        NavigationStack(path: navigationStack.binding) {
            MainScrollView(
                viewModel: .init()
            )
        }
        .toolbarBackground(.automatic, for: .navigationBar)
        .toolbar {
            ToolbarBuilder.toolBars()
        }
        .navigationDestination(for: NavigationLocation.self) { location in
            destinationView(location: location)
        }
        .navigationTitle("Group Words")
    }

    @ViewBuilder
    private func destinationView(location: NavigationLocation) -> some View {
        switch location {
            case let .cellDetailView(cell):
                CellDetailView(cell: cell)
            ....
        } 
    }
}

然后里面

MainScrollView
我有

struct MainScrollView: View {
    let viewModel: MainScrollViewModel

    // MARK: Body

    var body: some View {
        ScrollView {
            VStack(alignment: .leading) {
                ForEach(viewModel.cells, id: \.self) { cell in
                    NavigationLink(value: NavigationLocation.cellDetailView(cell)) {
                        CellView(cell: cell)
                    }
                    .buttonStyle(CellButtonStyle())
                }
            }
        }
    }
}



struct CellDetailView: View {
    var cell: ChildWordDetailViewModel

    var body: some View {
        Text(cell.name)
            .navigationTitle(cell.title)
            .navigationBarBackButtonHidden()
            .toolbar {
                ToolbarBuilder.toolBars()
            }
    }

}

最后,由于我的一些详细视图中有一个 TabView,我用它来允许滑回上一页。

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

    public func gestureRecognizer(
        _ gestureRecognizer: UIGestureRecognizer,
        shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer
    ) -> Bool {
        return gestureRecognizer.isEqual(self.interactivePopGestureRecognizer)
    }
}

我想这是我的

CustomNavigationStack

final class CustomNavigationStack: Navigator, ObservableObject {
    @Published private(set) var stack: [NavigationLocation] = []

    var binding: Binding<[NavigationLocation]> {
        Binding(
            get: { self.stack },
            set: { newValue in
                self.stack = newValue
            }
        )
    }

    func push(_ item: NavigationLocation) {
        stack.append(item)
    }

    func pop() {
        _ = stack.popLast()
    }
}

希望这有帮助

© www.soinside.com 2019 - 2024. All rights reserved.