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

SwiftUI中无需NavigationView/NavigationStack能否创建工具栏项?

问题

在SwiftUI中,使用NavigationStack时工具栏项可以正常显示,但将容器替换为VStack等组件后,工具栏项会消失。请问是否可以在不使用NavigationView/NavigationStack的情况下添加工具栏项?这对解决多视图间嵌套多个NavigationView的问题十分关键。

可正常运行的代码

import SwiftUI

struct Restaurant: Identifiable {
    let id = UUID()
    let name: String
}

// 单个餐厅的展示视图
struct RestaurantRow: View {
    var restaurant: Restaurant

    var body: some View {
        Text("Come and eat at \(restaurant.name)")
    }
}

struct SwiftUIView: View {
    let restaurants = [
        Restaurant(name: "Joe's Original"),
        Restaurant(name: "The Real Joe's Original"),
        Restaurant(name: "Original Joe's")
    ]
    
    var body: some View {
        NavigationStack {
            List(restaurants) { restaurant in
                RestaurantRow(restaurant: restaurant)
            }
            .toolbar {
                ToolbarItem(placement: .automatic) {
                    Text("Great Toolbar")
                }
            }
        }
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        SwiftUIView()
    }
}

无法显示工具栏项的代码

struct SwiftUIView: View {
    let restaurants = [
        Restaurant(name: "Joe's Original"),
        Restaurant(name: "The Real Joe's Original"),
        Restaurant(name: "Original Joe's")
    ]
    
    var body: some View {
        VStack {
            List(restaurants) { restaurant in
                RestaurantRow(restaurant: restaurant)
            }
            .toolbar {
                ToolbarItem(placement: .automatic) {
                    Text("Great Toolbar")
                }
            }
        }
    }
}
解决方案

SwiftUI原生的.toolbar修饰符默认依赖NavigationStack/NavigationView这类导航容器来渲染工具栏,脱离导航容器后没有对应的载体,所以工具栏会消失。不过有两种可行的替代方案:

方案一:自定义模拟工具栏

直接在布局中手动添加一个工具栏样式的视图,完全可控,适配所有iOS版本:

struct SwiftUIView: View {
    let restaurants = [
        Restaurant(name: "Joe's Original"),
        Restaurant(name: "The Real Joe's Original"),
        Restaurant(name: "Original Joe's")
    ]
    
    var body: some View {
        VStack(spacing: 0) {
            // 自定义顶部工具栏
            HStack {
                Spacer()
                Text("Great Toolbar")
                    .font(.headline)
                Spacer()
            }
            .padding(.vertical, 8)
            .background(Color(.systemBackground))
            .overlay(
                Divider().offset(y: 0.5)
            )
            
            List(restaurants) { restaurant in
                RestaurantRow(restaurant: restaurant)
            }
            .listStyle(.plain)
        }
    }
}

方案二:使用ToolbarContainer(iOS 16+)

iOS 16及以上版本提供了ToolbarContainer,可以独立承载工具栏,不需要嵌套导航栈:

struct SwiftUIView: View {
    let restaurants = [
        Restaurant(name: "Joe's Original"),
        Restaurant(name: "The Real Joe's Original"),
        Restaurant(name: "Original Joe's")
    ]
    
    var body: some View {
        VStack {
            List(restaurants) { restaurant in
                RestaurantRow(restaurant: restaurant)
            }
        }
        .toolbarContainer(.window) {
            ToolbarItem(placement: .primaryAction) {
                Text("Great Toolbar")
            }
        }
    }
}

两种方案对比:

  • 自定义工具栏:样式完全由你控制,适合需要个性化设计的场景,兼容所有iOS版本。
  • ToolbarContainer:贴合系统工具栏的原生行为,支持系统提供的placement位置配置,但仅支持iOS 16及以上版本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 02:55:19