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
相关产品推荐
相关产品推荐

