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

SwiftUI如何替换或隐藏第三方视图中的ToolbarItem

替换/隐藏第三方SwiftUI视图自带ToolbarItem的解决方法

第三方SDK提供的ThirdPartyView自带了导航栏左侧的ToolbarItem,当我们在自定义视图MyView中为其添加同位置的ToolbarItem时,两个按钮会并存显示,无法直接替换或隐藏原有按钮。相关代码如下:

第三方视图代码:

struct ThirdPartyView: View {
    var body: some View {
        VStack {
            Text("Hi!")
        }
        .toolbar {
            ToolbarItem(placement: .navigationBarLeading) {
                Image(systemName: "arrow.left")
            }
        }
    }
}

自定义视图代码:

struct MyView: View {
    var body: some View {
        ThirdPartyView()
        .toolbar {
            ToolbarItem(placement: .navigationBarLeading) {
                Image(systemName: "arrow.down")
            }
        }
    }
}

导航栈结构:

struct DisplayedView: View {
    var body: some View {
        NavigationStack {
            MyView()
        }
    }
}

方案一:通过UIKit API直接修改导航栏按钮(推荐保留系统导航栏样式时使用)

由于SwiftUI的Toolbar是累积式的,子视图和父视图的Toolbar会合并显示,因此可以借助UIKit的导航控制器API直接替换或清空原有按钮:

struct MyView: View {
    var body: some View {
        ThirdPartyView()
            .onAppear {
                guard let navVC = findTopNavigationController() else { return }
                // 替换为自定义按钮
                let customButton = UIBarButtonItem(
                    image: UIImage(systemName: "arrow.down"),
                    style: .plain,
                    target: nil,
                    action: #selector(customButtonTapped)
                )
                navVC.topViewController?.navigationItem.leftBarButtonItems = [customButton]
            }
            .onDisappear {
                // 页面消失时恢复原有状态(可选)
                guard let navVC = findTopNavigationController() else { return }
                navVC.topViewController?.navigationItem.leftBarButtonItems = nil
            }
    }
    
    @objc private func customButtonTapped() {
        // 自定义按钮的点击逻辑
    }
    
    // 找到当前最顶层的导航控制器
    private func findTopNavigationController() -> UINavigationController? {
        let keyWindow = UIApplication.shared.connectedScenes
            .filter { $0.activationState == .foregroundActive }
            .compactMap { $0 as? UIWindowScene }
            .first?
            .windows
            .first { $0.isKeyWindow }
        
        return keyWindow?.rootViewController?.topMost() as? UINavigationController
    }
}

// 扩展UIViewController,递归找到最顶层的视图控制器
extension UIViewController {
    func topMost() -> UIViewController {
        if let presented = presentedViewController {
            return presented.topMost()
        }
        if let nav = self as? UINavigationController {
            return nav.visibleViewController?.topMost() ?? nav
        }
        if let tab = self as? UITabBarController {
            return tab.selectedViewController?.topMost() ?? tab
        }
        return self
    }
}

方案二:隐藏原有导航栏,自定义导航栏(适合完全自定义样式时使用)

直接隐藏第三方视图的导航栏,然后自行构建导航栏组件:

struct MyView: View {
    var body: some View {
        VStack(spacing: 0) {
            // 自定义导航栏
            HStack {
                Image(systemName: "arrow.down")
                    .onTapGesture {
                        // 按钮点击逻辑
                    }
                Spacer()
            }
            .padding(.horizontal, 16)
            .padding(.vertical, 12)
            .background(Color(.systemBackground))
            
            // 隐藏第三方视图的导航栏
            ThirdPartyView()
                .toolbar(.hidden, for: .navigationBar)
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 22:47:46