Home > Software design >  How do I make conjoined buttons in SwiftUI? (MacOS)
How do I make conjoined buttons in SwiftUI? (MacOS)

Time:10-01

There are buttons present in apps, such as TextEdit where the sides of adjacent buttons are joined together. Does anyone know how I could replicate this visual? I'm working in SwiftUI on MacOS, and answers for MacOS 10 & 11 would be appreciated.

CodePudding user response:

I don’t think that’s possible in SwiftUI, unless you want to build it from scratch. What you’re seeing in TextEdit is an NSSegmentedControl that allows multiple selection: https://developer.apple.com/design/human-interface-guidelines/macos/selectors/segmented-controls/

In SwiftUI, segmented controls are made using Picker, which doesn’t allow multiple selection. Your best bet is to wrap NSSegmentedControl in an NSHostingView.

CodePudding user response:

Replicating these buttons using SwiftUI is not all that difficult. Here is a very basic approach, adjust the colors, corners etc... to your liking:

import SwiftUI

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct ContentView: View {
    var body: some View {
        TextFormats()
    }
}

struct GrayButtonStyle: ButtonStyle {
    let w: CGFloat
    let h: CGFloat
    
    init(w: CGFloat, h: CGFloat) {
        self.w = w
        self.h = h
    }
    
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .foregroundColor(Color.white)
            .frame(width: w, height: h)
            .padding(5)
            .background(Color(UIColor.systemGray4))
            .overlay(Rectangle().strokeBorder(Color.gray, lineWidth: 1))
    }
}

struct TextFormats: View {
    let sx = CGFloat(20)
    let color = Color.black
    
    @State var bold = false
    @State var italic = false
    @State var underline = false
    
    var body: some View {
        HStack (spacing: 0) {
            Group {
                Button(action: { bold.toggle() }) {
                    Image(systemName: "bold").resizable().frame(width: sx, height: sx)
                        .foregroundColor(bold ? .blue : color)
                }
                Button(action: { italic.toggle() }) {
                    Image(systemName: "italic").resizable().frame(width: sx, height: sx)
                        .foregroundColor(italic ? .blue : color)
                }
                Button(action: { underline.toggle() }) {
                    Image(systemName: "underline").resizable().frame(width: sx, height: sx)
                        .foregroundColor(underline ? .blue : color)
                }
            }.buttonStyle(GrayButtonStyle(w: sx 5, h: sx 5))
        }.padding(1)
            .overlay(RoundedRectangle(cornerRadius: 5).strokeBorder(.white, lineWidth: 2))
            .clipped(antialiased: true)
    }
    
}
  • Related