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

如何在macOS的SwiftUI Toolbar中创建可变宽度的ToolbarItems

注意:

本问题针对的是macOS平台的Toolbar,而非iOS。

背景

macOS应用里常见的设计范式是在NSWindow的工具栏中设置「状态区域」,比如Xcode的状态栏、Safari的地址栏:这类区域会随窗口放大缩小动态调整尺寸,而非固定宽度。

问题

如何在纯SwiftUI应用中实现该效果?用AppKit很容易做到,但在SwiftUI里,像下面代码中的场景该怎么操作:

struct MainWindowCenterPane: View
{
   var body: some View
   {
      ...
   }
   .toolbar {

      ToolbarItemGroup(placement: .navigation)  
      {
         // 左侧的一些按钮
      }

      ToolbarItemGroup(placement: .principal) 
      {
         Button { /* 紧贴状态栏左侧的按钮 */ }

         // 我的状态栏区域,希望它随窗口大小伸缩,
         // 限制最小和最大宽度。GeometryReader未能解决问题。
         ToolbarStatusView()

         Button { /* 紧贴状态栏右侧的按钮 */ }
      }
   }
}

解决方案

要实现可伸缩的工具栏状态区域,核心是利用SwiftUI的布局优先级与尺寸约束,以下是两种纯SwiftUI的可行方案:

方案一:给目标视图设置布局优先级与弹性尺寸

把需要伸缩的状态区域放在单独的ToolbarItem中,通过layoutPriority让它优先占据工具栏剩余空间,配合尺寸限制实现动态缩放:

struct MainWindowCenterPane: View
{
   var body: some View
   {
      Text("主内容区域")
   }
   .toolbar {

      ToolbarItemGroup(placement: .navigation)  
      {
         Button("返回") {}
         Button("前进") {}
      }

      ToolbarItemGroup(placement: .principal) 
      {
         Button { /* 左侧按钮 */ }

         ToolbarItem {
             ToolbarStatusView()
                 .frame(minWidth: 200, maxWidth: .infinity)
                 .layoutPriority(1) // 优先分配可用空间
         }

         Button { /* 右侧按钮 */ }
      }
   }
}

这里的layoutPriority(1)会让中间的状态视图优先获取工具栏的剩余宽度,minWidth和maxWidth则可以控制它的尺寸范围。

方案二:用弹性HStack包裹整个Principal区域

如果需要更精细的布局控制,可以将整个principal区域做成一个弹性HStack,让中间视图自动填充剩余空间:

struct CustomToolbar: ToolbarContent {
    var body: some ToolbarContent {
        ToolbarItemGroup(placement: .navigation) {
            Button("返回") {}
            Button("前进") {}
        }
        
        ToolbarItemGroup(placement: .principal) {
            HStack(spacing: 8) {
                Button("左侧操作") {}
                
                ToolbarStatusView()
                    .frame(minWidth: 200, maxWidth: .infinity)
                
                Button("右侧操作") {}
            }
            .frame(maxWidth: .infinity)
        }
    }
}

// 在视图中使用自定义工具栏
struct MainWindowCenterPane: View {
    var body: some View {
        Text("主内容区域")
            .toolbar { CustomToolbar() }
    }
}

这种方式让整个Principal区域成为一个弹性容器,两侧按钮保持固定位置,中间状态视图自动适配窗口宽度变化。

关键注意点

  • 必须给可伸缩视图设置maxWidth: .infinity,否则无法扩展到可用空间
  • layoutPriority是确保中间视图不被两侧按钮挤压的核心
  • 如果需要更复杂的尺寸逻辑,可以在ToolbarStatusView内部结合GeometryReader,但外层的布局优先级设置是基础

内容的提问来源于stack exchange,提问作者Bryan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 08:47:15