You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中NavigationLink跳转的SFSafariViewController Done按钮可点击区域过小问题

SwiftUI中NavigationLink集成SFSafariViewController的Done按钮点击区域异常问题

问题描述

通过程序化NavigationLink集成SFSafariViewController时,Done按钮仅“ne”部分特定角度可点击;改用sheet模态展示时按钮功能正常,但需保留NavigationLink跳转方式。

解决方案

方案1:使用NavigationPath替代isActive式导航

改用NavigationStack+NavigationPath管理导航,规避旧版isActive导航可能引发的层级冲突:

// HomeView 实现
struct HomeView: View {
    @State private var navigationPath = NavigationPath()

    var body: some View {
        NavigationStack(path: $navigationPath) {
            VStack(spacing: 0) {
                Spacer()
                Button("Show Website") {
                    navigationPath.append(URL(string: "https://www.example.com")!)
                }
                Spacer()
            }
            .navigationDestination(for: URL.self) { url in
                SafariView(url: url)
                    .navigationBarHidden(true)
            }
        }
    }
}

// SafariView 保留原实现不变

方案2:通过绑定状态同步导航激活状态

移除@Environment(\.dismiss),改用绑定状态控制导航激活,避免环境 Dismiss 与SFSafariVC原生按钮的交互冲突:

// 修改后的SafariView
struct SafariView: UIViewControllerRepresentable {
    @Binding var isActive: Bool
    let url: URL

    func makeUIViewController(context: Context) -> SFSafariViewController {
        let vc = SFSafariViewController(url: url)
        vc.preferredControlTintColor = .tintColor
        vc.delegate = context.coordinator
        return vc
    }

    func updateUIViewController(_ vc: SFSafariViewController, context: Context) {}

    class Coordinator: NSObject, SFSafariViewControllerDelegate {
        private let isActive: Binding<Bool>

        init(isActive: Binding<Bool>) {
            self.isActive = isActive
        }

        func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
            isActive.wrappedValue = false
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(isActive: $isActive)
    }
}

// 修改后的HomeView
struct HomeView: View {
    @State private var isBtnActive: Bool = false

    var body: some View {
        NavigationStack {
            NavigationLink(
                destination: SafariView(isActive: $isBtnActive, url: URL(string: "https://www.example.com")!)
                    .navigationBarHidden(true),
                isActive: $isBtnActive,
                label: { EmptyView() }
            )
            .accessibilityHidden(true)

            VStack(spacing: 0) {
                Spacer()
                Button("Show Website") {
                    isBtnActive = true
                }
                Spacer()
            }
        }
    }
}

方案3:添加安全区域忽略

让SafariView完全占据导航栈视图空间,避免SwiftUI布局元素遮挡按钮:

// 修改HomeView中的NavigationLink部分
NavigationLink(
    destination: SafariView(url: URL(string: "https://www.example.com")!)
        .edgesIgnoringSafeArea(.all)
        .navigationBarHidden(true),
    isActive: $isBtnActive,
    label: { EmptyView() }
)

问题根源

SwiftUI导航栈与SFSafariViewController的导航栏存在层级或布局冲突,导致Done按钮部分区域被SwiftUI的透明布局元素遮挡。上述方案从导航管理、状态同步、布局占比三个维度解决该冲突。

内容的提问来源于stack exchange,提问作者kittonian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 08:15:01