如何在SwiftUI(MacOS)中实现连体按钮效果?
macOS SwiftUI 连体相邻按钮实现方案(兼容10.15 / 11.x 版本)
实现逻辑
- macOS 11+ 系统原生提供
ControlGroup组件,默认自带和TextEdit一致的连体按钮样式,无需额外自定义 - macOS 10.15 没有对应原生组件,通过自定义视图组合、手动控制圆角和边框的方式模拟效果
完整可运行代码
import SwiftUI // 跨版本兼容连体按钮组容器 struct JoinedButtonGroup<Content: View>: View { let content: Content init(@ViewBuilder content: () -> Content) { self.content = content() } var body: some View { if #available(macOS 11.0, *) { ControlGroup { content } .controlGroupStyle(.automatic) } else { HStack(spacing: 0) { content } .overlay( RoundedRectangle(cornerRadius: 6) .stroke(Color.secondary.opacity(0.3), lineWidth: 1) ) .cornerRadius(6) } } } // 按钮样式扩展,适配连体效果 extension Button { func joinedButtonStyle(isFirst: Bool = false, isLast: Bool = false) -> some View { if #available(macOS 11.0, *) { return self } else { return self .buttonStyle(BorderlessButtonStyle()) .padding(.horizontal, 12) .padding(.vertical, 6) .background( Rectangle() .fill(Color.clear) .overlay( Rectangle() .fill(Color.secondary.opacity(0.3)) .frame(width: 1), alignment: .trailing ) .opacity(isLast ? 0 : 1) ) .cornerRadius(6, corners: isFirst ? [.topLeft, .bottomLeft] : []) .cornerRadius(6, corners: isLast ? [.topRight, .bottomRight] : []) } } } // 辅助工具:指定圆角位置 extension View { func cornerRadius(_ radius: CGFloat, corners: RectCorner) -> some View { clipShape(RoundedCorner(radius: radius, corners: corners)) } } struct RoundedCorner: Shape { var radius: CGFloat = .infinity var corners: RectCorner = .allCorners func path(in rect: CGRect) -> Path { let path = NSBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: NSSize(width: radius, height: radius)) return Path(path.cgPath) } }
使用示例
struct ContentView: View { var body: some View { JoinedButtonGroup { Button("加粗") { // 业务逻辑 } .joinedButtonStyle(isFirst: true) Button("斜体") { // 业务逻辑 } .joinedButtonStyle() Button("下划线") { // 业务逻辑 } .joinedButtonStyle(isLast: true) } .padding() .frame(width: 300, height: 150) } }
样式调整说明
- 可修改
cornerRadius参数值匹配App的整体设计风格 - 按钮内边距、分隔线颜色、边框宽度都可根据需求自定义调整
- 11+版本可通过修改
controlGroupStyle参数切换不同的原生连体样式
内容的提问来源于stack exchange,提问作者Caleb Chervenka
相关产品推荐
相关产品推荐

