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

如何在iOS 13上实现被UIHostingController包裹的SwiftUI View自定义返回按钮并弹出导航栈?

针对iOS 13的自定义返回按钮解决方案

针对iOS 13的场景,你遇到的问题其实是因为SwiftUI View被UIHostingController包裹后,和UIKit导航栈的交互逻辑需要结合UIKit的API来处理——直接用纯SwiftUI的导航弹出方法会因为两层导航容器的兼容问题失效。下面给你两个可靠的解决方案:

方案一:通过闭包让SwiftUI触发UIKit的弹出动作

这种方式让SwiftUI视图持有一个来自UIHostingController的闭包,点击自定义按钮时直接调用闭包完成弹出,逻辑清晰且避免强引用问题:

1. 定义带弹出闭包的SwiftUI视图

struct TransactionDetailsView: View {
    let transactionRecord: YourRecordType // 替换成你的记录类型
    let onPop: () -> Void
    
    var body: some View {
        // 你的页面内容
        ScrollView {
            Text("交易详情:\(transactionRecord.description)")
                .padding()
        }
        // 设置自定义返回按钮
        .navigationBarItems(leading: Button(action: onPop) {
            HStack(spacing: 4) {
                Image(systemName: "chevron.left") // iOS13支持SF Symbols,若不支持可替换为自定义图片
                Text("返回")
            }
        })
        .navigationBarTitle("交易详情", displayMode: .inline)
    }
}

2. 修改UIHostingController的初始化逻辑

class TransactionDetailsHostingController: UIHostingController<TransactionDetailsView> {
    init(transactionRecord: YourRecordType) {
        // 传递弹出闭包,用weak self避免循环引用
        let rootView = TransactionDetailsView(transactionRecord: transactionRecord) { [weak self] in
            self?.navigationController?.popViewController(animated: true)
        }
        super.init(rootView: rootView)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 隐藏系统默认返回按钮,避免和自定义按钮冲突
        navigationItem.hidesBackButton = true
    }
}

方案二:直接在UIHostingController中设置UIKit风格的导航按钮

如果你不想在SwiftUI视图中处理导航逻辑,可以直接在UIHostingController层面配置自定义返回按钮,完全用UIKit的API实现:

class TransactionDetailsHostingController: UIHostingController<TransactionDetailsView> {
    init(transactionRecord: YourRecordType) {
        super.init(rootView: TransactionDetailsView(transactionRecord: transactionRecord))
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 隐藏系统默认返回按钮
        navigationItem.hidesBackButton = true
        
        // 创建自定义返回按钮
        let backButton = UIBarButtonItem(
            image: UIImage(systemName: "chevron.left"),
            style: .plain,
            target: self,
            action: #selector(popViewController)
        )
        // 可选:给按钮添加文字
        // backButton.title = "返回"
        navigationItem.leftBarButtonItem = backButton
    }
    
    @objc private func popViewController() {
        navigationController?.popViewController(animated: true)
    }
}

关键注意事项

  • 必须调用navigationItem.hidesBackButton = true隐藏系统默认返回按钮,否则会出现两个返回按钮
  • 闭包方案中一定要用[weak self]避免循环引用,防止内存泄漏
  • iOS13中使用UIImage(systemName:)需要确保项目支持SF Symbols(Xcode 11+默认支持),如果需要兼容更早的环境,替换为自定义图片即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 15:12:41