skip to Main Content

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.

2

Answers


  1. 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.

    Login or Signup to reply.
  2. 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)
        }
        
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search