Reputation: 1198
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!
Upvotes: 20
Views: 5345
Reputation: 2835
Maybe you already figured this out, but the way you're supposed to do it now is to use both .menuStyle(.button)
and then .buttonStyle(.bordered)
in sequence. They deprecated the borderedButton menuStyle https://developer.apple.com/documentation/swiftui/menustyle/borderedbutton
so once its a button you can style it anyway you like or change its color etc just like a button. I was just thinking of bordered button style as an example.
Upvotes: 2
Reputation: 58583
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)
}
}
}
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)
}
}
}
P.S.
Tested on iOS 15.5 and macOS 12.4.
Upvotes: 2