如何实现类似Finder中NSToolbar分段控件空间不足时自动折叠的效果
NSToolbar分段控件自动折叠实现方案
要实现Finder工具栏中分段控件空间不足时自动折叠为下拉菜单的效果,可按以下方案实现:
macOS 11+ 原生实现(推荐)
不要使用NSToolbarItem挂载自定义NSSegmentedControl的方案,改用系统原生提供的NSToolbarItemGroup API,该组件原生支持自动折叠逻辑:
- 替换原有自定义分段控件,使用
NSToolbarItemGroup(segmentedSubitems:)构造器创建工具栏组,将原分段控件的每个选项对应为独立的NSToolbarItem传入构造器 - 保持
isMenuFormRepresentationEnabled属性为默认的true,系统会自动判断工具栏可用空间:空间充足时展示完整分段控件,空间不足时自动折叠为单个下拉按钮,点击可展开所有选项 - 可根据需求设置
selectionMode属性控制分段的单选/多选逻辑,也可重写menuFormRepresentation属性自定义折叠后菜单项的展示内容、快捷键和触发动作
示例代码:
import AppKit func buildSegmentedToolbarGroup() -> NSToolbarItemGroup { // 配置每个分段对应的工具栏项 let previewItem = NSToolbarItem(itemIdentifier: .init("preview")) previewItem.title = "预览" previewItem.image = NSImage(systemSymbolName: "eye", accessibilityDescription: "预览") previewItem.action = #selector(triggerPreview(_:)) let shareItem = NSToolbarItem(itemIdentifier: .init("share")) shareItem.title = "分享" shareItem.image = NSImage(systemSymbolName: "square.and.arrow.up", accessibilityDescription: "分享") shareItem.action = #selector(triggerShare(_:)) let deleteItem = NSToolbarItem(itemIdentifier: .init("delete")) deleteItem.title = "删除" deleteItem.image = NSImage(systemSymbolName: "trash", accessibilityDescription: "删除") deleteItem.action = #selector(triggerDelete(_:)) // 生成分段组,自动处理折叠逻辑 let segmentGroup = NSToolbarItemGroup(segmentedSubitems: [previewItem, shareItem, deleteItem]) segmentGroup.selectionMode = .selectOne segmentGroup.isMenuFormRepresentationEnabled = true return segmentGroup }
注意:不要给
NSToolbarItemGroup设置自定义view属性,设置自定义视图后系统会禁用原生自动布局、折叠逻辑,所有展示规则需要自行实现。
低版本兼容方案
如果应用需要支持macOS 11以下系统,需要手动实现折叠逻辑:
- 监听
NSToolbar.didResizeNotification通知,获取工具栏实时尺寸 - 提前计算完整分段控件展示需要的最小宽度阈值
- 当工具栏可用宽度小于阈值时,将分段控件替换为单个按钮,点击按钮弹出预置了所有分段选项的菜单,模拟折叠效果
内容的提问来源于stack exchange,提问作者Deitsch
相关产品推荐
相关产品推荐

