如何设置macOS三栏NavigationView中间Itembar列的宽度
问题原因
macOS 上三栏样式的NavigationView本质是对NSSplitViewController的封装,每一列的宽度由分割视图的列配置统一管理,你给Itembar内部列表设置的frame只会作用于列表本身,无法影响上层分割列的宽度规则,所以会出现minWidth不生效的问题。
解决方案
方案1:使用官方推荐的NavigationSplitView(兼容 macOS 13+)
苹果从SwiftUI 4开始推出了专门用于多栏布局的NavigationSplitView组件,原生支持各列宽度自定义,是现在三栏布局的首选实现。
你需要将分散在子视图的选中状态提升到父视图统一管理,同时为每一列单独设置宽度规则,修改后的完整代码如下:
import SwiftUI struct Group: Identifiable, Hashable { let id = UUID() let name: String let items: [String] } let groups = [ Group(name: "Group A", items: ["Item 1", "Item 2"]), Group(name: "Group B", items: ["Item 3"]), Group(name: "Group C", items: ["Item 4", "Item 5", "Item 6"]) ] struct ContentView: View { @State private var selectedGroup: Group? @State private var selectedItem: String? var body: some View { NavigationSplitView { // 侧边栏(第一列) List(groups, selection: $selectedGroup) { group in Text(group.name).tag(group) } .navigationSplitViewColumnWidth(min: 150, ideal: 180) .listStyle(.sidebar) .toolbar { Button( action: { NSApp.keyWindow?.contentViewController?.tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil) }, label: { Label("Toggle sidebar", systemImage: "sidebar.left") }) } } content: { // 中间Item栏(第二列) if let selectedGroup { List(selectedGroup.items, selection: $selectedItem) { item in Text(item).tag(item) } .navigationSplitViewColumnWidth(min: 100, ideal: 150) } else { Text("Select a Group") } } detail: { // 详情栏(第三列) if let selectedItem { Text("The selection is \(selectedItem)") } else { Text("Select an Item") } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
通过navigationSplitViewColumnWidth可以分别设置每一列的最小宽度、理想默认宽度、最大宽度,完全符合你的自定义需求。
方案2:老版本兼容方案(支持 macOS 12及更低版本)
如果需要兼容旧版系统,要继续使用原有NavigationView实现的话,只需要给Itembar的根视图添加fixedSize修饰符,强制视图抵抗父视图的宽度压缩,你设置的minWidth就会生效:
struct Itembar: View { let items: [String] @State private var selection: String? var body: some View { List(items, id: \.self) { item in NavigationLink(item, destination: DetailView(detailText: item), tag: item, selection: $selection) } .frame(minWidth: 100, idealWidth: 150) // 横向固定尺寸,纵向自适应 .fixedSize(horizontal: true, vertical: false) } }
内容的提问来源于stack exchange,提问作者wigging
相关产品推荐
相关产品推荐

