如何根据各列上方Toolbar宽度动态设置NavigationSplitView最小列宽?
要实现根据Toolbar宽度动态限制NavigationSplitView对应列的最小宽度,核心思路是捕获Toolbar的实际宽度,并将其传递给列的最小宽度配置。以下是具体实现步骤:
1. 定义PreferenceKey捕获Toolbar宽度
首先创建一个PreferenceKey,用于在视图层级间传递Toolbar的宽度值:
struct ToolbarWidthPreferenceKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = max(value, nextValue()) } }
2. 在Toolbar视图中注入宽度捕获逻辑
修改你的RadioToolbarView,用GeometryReader包裹内容并传递宽度到PreferenceKey:
struct RadioToolbarView: View { @Binding var options: Options var body: some View { HStack(spacing: 16) { ForEach(options.options) { option in Button(option.name) { options.selection = option.name } .buttonStyle(.borderedProminent) .tint(options.selection == option.name ? .blue : .gray) } } .background( GeometryReader { proxy in Color.clear .preference(key: ToolbarWidthPreferenceKey.self, value: proxy.size.width) } ) } }
3. 用ObservableObject传递宽度值
创建一个可观察对象,用于在CertsView和ContentView之间共享宽度数据:
class SplitViewColumnWidths: ObservableObject { @Published var certsColumnMinWidth: CGFloat = 0 }
4. 在ContentView中配置列最小宽度
修改ContentView,注入宽度管理对象并设置列的最小宽度:
struct ContentView: View { @StateObject private var columnWidths = SplitViewColumnWidths() var body: some View { NavigationSplitView { CustomersView() } content: { CertsView(columnWidths: columnWidths) .navigationSplitViewColumnWidth(min: columnWidths.certsColumnMinWidth) } detail: { DetailsView() } .background(Color.white) .controlSize(.large) } }
5. 在CertsView中接收并更新宽度值
修改CertsView,监听Toolbar宽度变化并更新共享的最小宽度值(可额外添加边距优化视觉效果):
struct CertsView: View { @State var filterOptions: Options = Options( options: [ Option(name: "All"), Option(name: "Running"), Option(name: "Valid") ], selection: "All" ) @ObservedObject var columnWidths: SplitViewColumnWidths var body: some View { VStack { Text(filterOptions.selection) .toolbar { RadioToolbarView(options: $filterOptions) } } .onPreferenceChange(ToolbarWidthPreferenceKey.self) { newWidth in // 添加额外边距避免内容拥挤,数值可按需调整 columnWidths.certsColumnMinWidth = newWidth + 32 } } }
补充:确保数据模型可识别
如果你的Option还未实现Identifiable,需补充以支持ForEach遍历:
struct Option: Identifiable { let id = UUID() var name: String } struct Options { var options: [Option] var selection: String }
效果说明
- 当Toolbar内容宽度变化时(比如选项增减、文本长度变化),列的最小宽度会自动更新
- 拖动列边界时,无法将列宽度缩小到小于Toolbar的实际宽度+边距,避免Toolbar内容被截断
内容的提问来源于stack exchange,提问作者George Papadopoulos
相关产品推荐
相关产品推荐

