I'm creating a custom toolbar, in SwiftUI, for a macOS app. I have the buttons styled the way I want, but now I want to put some buttons in a ControlGroup. The problem is that all styling I created for the buttons is lost; what would be a suitable way to get the ControlGroup to keep the styling I have used on the buttons?
From playground preview without & with the ControlGroup.
The playground code.
import SwiftUI
import PlaygroundSupport
enum ToolButtonType: String {
case none = ""
case pointer = "cursorarrow"
case pin = "mappin"
case line = "pencil.line"
case polyline = "scribble"
case polygon = "skew"
case measure = "ruler"
case select = "dot.viewfinder"
case dragselect = "viewfinder"
case properties = "info.square"
}
let fixedTools: [ToolButtonType] = [
.properties
]
struct FixedToolButtonStyle: ButtonStyle {
var type: ToolButtonType
let height: CGFloat = 48
let width: CGFloat = 48
let cornerRadius: CGFloat = 3
var bgColor: Color { Color.accentColor }
var fgColor: Color { Color.primary }
let fontSize: CGFloat = 24
let weight: Font.Weight = .semibold
let textSidePadding: CGFloat = 0
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding([.all], textSidePadding)
.frame(minWidth: width, maxWidth: width, minHeight: height, maxHeight: height)
.background(bgColor)
.foregroundColor(fgColor)
.cornerRadius(cornerRadius)
.font(.system(size: fontSize, weight: weight, design: .default))
.scaleEffect(configuration.isPressed ? 0.8 : 1)
.animation(.easeOut(duration: 0.2), value: configuration.isPressed)
}
}
struct FixedToolButtonView: View {
var type: ToolButtonType
var name: String { type.rawValue }
var body: some View {
Button(action: {
print("Pressed: \(type)")
}) {
Text("\(Image(systemName: type.rawValue))")
}
.buttonStyle(FixedToolButtonStyle(type: type))
}
}
let selectableTools: [ToolButtonType] = [
.pointer,
.pin,
.line,
.polyline,
.polygon,
.measure,
.select,
.dragselect,
]
struct SelectableToolButtonStyle: ButtonStyle {
var type: ToolButtonType
var isSelected: Bool
let height: CGFloat = 48
let width: CGFloat = 48
let cornerRadius: CGFloat = 3
var bgColor: Color {
return !isSelected ? Color.black : Color.accentColor
}
var fgColor: Color {
return isSelected ? Color.primary : Color.secondary
}
let fontSize: CGFloat = 24
let weight: Font.Weight = .semibold
let textSidePadding: CGFloat = 0
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding([.all], textSidePadding)
.frame(minWidth: width, maxWidth: width, minHeight: height, maxHeight: height)
.background(bgColor)
.foregroundColor(fgColor)
.cornerRadius(cornerRadius)
.font(.system(size: fontSize, weight: weight, design: .default))
.scaleEffect(configuration.isPressed ? 0.8 : 1)
.animation(.easeOut(duration: 0.2), value: configuration.isPressed)
}
}
struct SelectableToolButtonView: View {
var type: ToolButtonType
var name: String { type.rawValue }
@Binding var selectedTool: ToolButtonType
var body: some View {
Button(action: {
self.selectedTool = type
print("Pressed: \(type)")
}) {
Text("\(Image(systemName: type.rawValue))")
}
.buttonStyle(SelectableToolButtonStyle(type: type, isSelected: selectedTool == type))
}
}
struct ToolBarView: View {
@Binding var selectedTool: ToolButtonType
var body: some View {
HStack {
// ControlGroup {
ForEach(selectableTools, id: \.self) { tool in
SelectableToolButtonView(type: tool, selectedTool: $selectedTool)
}
// }
Spacer()
ForEach(fixedTools, id: \.self) { tool in
FixedToolButtonView(type: tool)
}
}
}
}
struct ContentView: View {
@State var selectedTool: ToolButtonType = .none
var body: some View {
ToolBarView(selectedTool: $selectedTool)
}
}
let vw = ContentView()
PlaygroundPage.current.setLiveView(vw)