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

如何根据各列上方Toolbar宽度动态设置NavigationSplitView最小列宽?

动态设置NavigationSplitView列最小宽度适配Toolbar宽度

要实现根据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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 15:46:22