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

iOS17中NavigationStack自定义返回按钮点击后黑屏问题求助

解决iOS17 + Xcode15中NavigationStack自定义返回按钮页面变黑的问题

升级到iOS17与Xcode15后,使用NavigationStack的自定义返回按钮调用path.removeLast()时,页面会先变黑再返回至InitView,但侧滑返回功能正常。iOS17之前点击返回按钮会平滑侧滑关闭页面,无此问题。


相关代码

InitView

NavigationStack {
    // 页面内容
}
.navigationDestination(for: String.self) { route in
    switch route {
        case "LoginView":
            LoginView(path: $path)
        case "RegisterView":
            RegisterView(path: $path)
        case "ResetPasswordView":
            ResetPasswordView(path: $path)
        default:
            Text("Unknown")
    }
}

LoginView

struct LoginView: View {
    @Binding var path: NavigationPath
    var body: some View {
        VStack {
            Button(action: {
                // 此代码不会触发黑屏
                // self.presentationMode.wrappedValue.dismiss()
                
                // 此代码会导致LoginView先变黑再返回InitView
                path.removeLast()
            }, label: {
                ZStack {
                    RoundedRectangle(cornerRadius: 7)
                        .stroke(.gray.opacity(0.3), lineWidth: 3)
                        .frame(width: 30, height: 30)
                    Image(systemName: "chevron.left")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: 8)
                        .bold()
                        .foregroundColor(.gray)
                }
            })
        }
        .navigationBarBackButtonHidden()
    }
 }

恢复侧滑返回的扩展代码

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

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

    // 让侧滑在ScrollView中也能生效
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        true
    }
}

解决方案

这个问题是iOS17中NavigationStack的path操作与自定义导航栏隐藏结合时的动画兼容问题,可通过以下方式解决:

方式一:使用环境变量的dismiss方法

在子视图中注入NavigationStack的环境代理,调用官方返回方法保留平滑动画:

struct LoginView: View {
    @Binding var path: NavigationPath
    @Environment(\.dismiss) private var dismiss // 新增环境变量
    
    var body: some View {
        VStack {
            Button(action: {
                dismiss() // 使用官方dismiss方法
            }, label: {
                // 按钮UI保持不变
                ZStack {
                    RoundedRectangle(cornerRadius: 7)
                        .stroke(.gray.opacity(0.3), lineWidth: 3)
                        .frame(width: 30, height: 30)
                    Image(systemName: "chevron.left")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: 8)
                        .bold()
                        .foregroundColor(.gray)
                }
            })
        }
        .navigationBarBackButtonHidden()
    }
 }

方式二:给path操作添加显式动画

如果必须使用path.removeLast(),将操作包裹在withAnimation中强制启用导航转场动画:

Button(action: {
    withAnimation(.default) {
        path.removeLast()
    }
}, label: {
    // 按钮UI保持不变
})

方式三:调整侧滑扩展逻辑

全局UINavigationController扩展可能干扰iOS17的导航动画,修改扩展仅在必要时启用侧滑:

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

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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 05:37:21