Home > Net >  How do you create a Preferences Style toolbar in SwiftUI for macOS?
How do you create a Preferences Style toolbar in SwiftUI for macOS?

Time:09-29

I am trying to create a Preferences style toolbar (Icon over text) for my SwiftUI Settings view on macOS. Using the following code:

struct PreferencesView: View {
    
    //MARK: Constants and Variables
    
    @AppStorage("authToken") var authToken: String = ""
    @AppStorage("author") var author: String = ""

    
    //MARK: Main
    var body: some View {
        VStack {
            HStack {
                VStack (alignment: .leading, spacing: 10) {
                    Text("Author:")
                    Text("GitHub Auth Token:")
                }
                VStack {
                    TextField("", text: $author)
                    TextField("", text: $authToken)
                }
            }
            .padding()
            
            Spacer()
        }

        .toolbar {
            ToolbarItem(placement: .principal) {
                Button {
                } label: {
                    Label {
                        Text("General")
                    } icon: {
                        Image (systemName: "gearshape")
                    }
                    .labelStyle (VerticalLabelStyle()) //custom label style
                }
            }
        }
        .frame(width: 480, height: 320)
    }
}

The result is a button whose only bottom is shown.

enter image description here

The Label Style is defined as such:

struct VerticalLabelStyle: LabelStyle {

    @ViewBuilder
    func makeBody(configuration: Configuration) -> some View {
        VStack {
            configuration.icon
                .font(.largeTitle)
            configuration.title
        }
    }
}

Anyone know how to create this successfully in SwiftUI on macOS?

CodePudding user response:

Are you using the SwiftUI App Lifecycle? If so, add a TabView to your Settings view and the tabs will appear in the toolbar automatically:

Settings {
    TabView {
        PreferencesView()
            .tabItem {
                Label("General", systemImage: "gearshape")
            }
    }
}

If you’re not using the SwiftUI app lifecycle, then I think you’ll need to build this style of toolbar manually using NSToolbar.

CodePudding user response:

Here a possible way for you:

enter image description here

struct ContentView: View {
    
    @AppStorage("authToken") var authToken: String = ""
    @AppStorage("author") var author: String = ""

    var body: some View {
        VStack {
            HStack {
                VStack (alignment: .leading, spacing: 10) {
                    Text("Author:")
                    Text("GitHub Auth Token:")
                }
                VStack {
                    TextField("", text: $author)
                    TextField("", text: $authToken)
                }
            }
            .padding()
            
            Spacer()
        }
        .toolbar(content: {
            
            ToolbarItem(placement: .principal) {

                HStack {
                    
                    ToolbarItemView(string: "General", imageSystemName: "gearshape", action: actionOfGeneral)
                    
                    ToolbarItemView(string: "About", imageSystemName: "info.circle", action: actionOfAbout)
                }
 
            }
            
        })
        .frame(width: 480, height: 320)
    }
    
    private func actionOfGeneral() { print("General clicked!") }
    private func actionOfAbout() { print("About clicked!") }

}


struct ToolbarItemView: View {
    
    let string: String
    let imageSystemName: String
    let action: () -> Void
    
    @State private var isPressing: Bool = Bool()
    var body: some View {
        
        VStack(spacing: 2.0) {
            Image(systemName: imageSystemName)
            Text(string)
        }
        .frame(width: 50)
        .background(Color.white.opacity(0.01))
        .padding(.horizontal, 5.0)
        .padding(.vertical, 2.0)
        .overlay(RoundedRectangle(cornerRadius: 5.0).stroke(Color.secondary.opacity(0.5), style: StrokeStyle(lineWidth: 1.0)))
        .opacity(isPressing ? 0.75 : 1.0)
        .scaleEffect(isPressing ? 0.95 : 1.0)
        .gesture(DragGesture(minimumDistance: .zero, coordinateSpace: .local).onChanged { _ in isPressing = true }.onEnded { _ in isPressing = false; action() })
        .animation(Animation.interactiveSpring(), value: isPressing)
        
    }
    
}

CodePudding user response:

I found the Apple recommended way of doing this by putting in a TabView. Works great.

var body: some View {
        TabView {
            GeneralSettingsView
                .tabItem {
                    Label("General", systemImage: "gearshape")
                }
        }
    }
  • Related