Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI: Is there any way to add a custom button style to a Menu()?

I have been trying for quite some time to add a custom button style/behavior to the label of a SwiftUI Menu() but haven't had any success so far. Here is an example of what I want to achieve:

Custom Button Style

Let's assume I have a custom Button Style that lets a button's text become red when pressed.

struct RedButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundColor(configuration.isPressed ? .red : .primary)
}

Menu

Also, I have a standard SwiftUI menu.

Menu("Menu button", content: {
    // Some menu content goes here
})

In this configuration the SwiftUI menu displays a standard button in the accent color (system blue) that behaves like a standard button (getting greyed out when pressed). When pressed, the menu is shown as expected.

Custom menu button

Now I want to somehow apply the custom button style to the button the menu is using. What I tried was the following:

Menu(content: {
    // Some menu content goes here
}, label: {
    Button("Menu button", action: { })
        .buttonStyle(RedButtonStyle())
})

However, the behavior of the menu's button is not changing at all - it's still just getting greyed out when being pressed, not getting colored red.

I also experimented a bit with creating a custom MenuStyle but haven't had any success so far.

Any suggestions on this? Thanks!

like image 320
Malburrito Avatar asked Jul 15 '21 20:07

Malburrito


People also ask

How do I create a button action in SwiftUI?

SwiftUI's button is similar to UIButton , except it's more flexible in terms of what content it shows and it uses a closure for its action rather than the old target/action system. To create a button with a string title you would start with code like this: Button("Button title") { print("Button tapped!") }

How do I create a custom view in SwiftUI?

Use SwiftUI Views From Other Frameworks To get started, you'll create a new custom view to manage your map. Choose File > New > File, select iOS as the platform, select the “SwiftUI View” template, and click Next. Name the new file MapView. swift and click Create.

How do I enable and disable a button in SwiftUI?

SwiftUI lets us disable any part of its forms or even the whole form, all by using the disabled() modifier. This takes a single Boolean that defines whether the element should be disabled or not. The form element's style automatically gets updated to reflect its status – buttons and toggles get grayed out, for example.


1 Answers

Menu's label color

In iOS 15.0+, there's the init(_:role:action:) initializer that allows you create a red label color using .destructive role. If you're not intending to delete user data, use this role for your button. Here's how the code may look like:

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        ZStack {
            Color.black.ignoresSafeArea()
            
            Menu("Actions") {
                Button(role: .destructive, action: { }) {
                    Label("Apple Swift 6.0", systemImage: "swift")
                        .font(.largeTitle)
                }
            }
            .font(.largeTitle)
            .foregroundColor(.yellow)              
        }
    }
}

enter image description here

Menu's button colors

Here's my workaround for changing Menu's button text color.

import SwiftUI

struct ContentView: View {
    
    @State private var color: Color = .red
    
    var body: some View {
        
        let press = LongPressGesture(minimumDuration: 0.0001)
                                         .onChanged { _ in color = .yellow }
                                         .onEnded { _ in color = .red }

        ZStack {
            Color.black.ignoresSafeArea()
            
            Menu("Choose") {
                Button(role: .none, action: { }) {
                    Label("Apple Swift 6.0", systemImage: "swift")
                }
            }
            .font(.largeTitle)
            .foregroundColor(color)
            .gesture(press)
        }
    }
}

enter image description here

P.S.

Tested on iOS 15.5 and macOS 12.4.

like image 119
Andy Jazz Avatar answered Jan 05 '23 00:01

Andy Jazz