Reputation: 2040
I'm creating an iOS app using Apple's SwiftUI framework. As I need to detect if the user taps on a specific area of the screen, I obviously use a button.
The problem is that the area contains an Image and a Text, and as the button automatically gives its content the blue color, the image is also colored, so instead of being an Image it's just a blue rounded rectangle.
It is said that an image is worth a thousand words, and as I'm not good at explaining, here you have a graphic demonstration of what happens:
Outside the button (without button styling)
Inside the button (with button styling)
This happens because the button is adding .foregroundColor(.blue)
to the image.
How can I avoid/disable the button adding style to its components?
EDIT: This is my button code:
ContentView.swift:
Button(action: {/* other code */}) {
PackageManagerRow(packageManager: packageManagersData[0])
}
PackageManagerRow.swift:
struct PackageManagerRow : View {
var packageManager : PackageManager
var body: some View {
VStack {
HStack {
Image(packageManager.imageName)
.resizable()
.frame(width: 42.0, height: 42.0)
Text(verbatim: packageManager.name)
Spacer()
Image(systemName: "checkmark")
.foregroundColor(.blue)
.opacity(0)
}.padding(.bottom, 0)
Divider()
.padding(.top, -3)
}
}
}
Upvotes: 13
Views: 10054
Reputation: 1385
If you are managing yourself all the customisation of a button, then using the .buttonStyle(.plain)
is good but not enough, as said in its documentation, it only disables some styling, not all of them.
i.e. presssed would still be managed by SwiftUI.
If you want 0 modification from SwiftUI on your Button, you have to create a Custom Style that does nothing
struct NoButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
return configuration.label
}
}
// Then use
// .buttonStyle(NoButtonStyle())
// And voila
Upvotes: 8
Reputation: 10839
Apply the style .plain
to your button to avoid overlay color.
// Before
Button(...)
// After
Button(...)
.buttonStyle(.plain) // Remove the overlay color (blue) for images inside Button
.plain
button style, that doesn’t style or decorate its content while idle, but may apply a visual effect to indicate the pressed, focused, or enabled state of the button.Another solution is to custom the style with ButtonStyle
like: struct MyButtonStyle:ButtonStyle { }
Upvotes: 1
Reputation: 5125
A button with an icon! How original 😀. If you are dealing with SF symbols then the following will do fine:
Button(action: addItem) {
Text(Image(systemName: "plus").renderingMode(.original))
+
Text("This is Plus")
}
.font(.system(size: 42))
The limitation of the option above is you don't have control over Image
's size. So for custom images the following is more appropriate:
Button(action: addItem) {
Label(
title: { Text("Label").font(.system(size: 40)) }, // Any font you like
icon: { Image(systemName: "rectangle.and.pencil.and.ellipsis") // Both custom and system images, i.e. `Image("Cydia logo")`
.renderingMode(.original)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 42, height: 42) // Any size you like
.padding() // Any padding you need
} // and etc.
)
}
Upvotes: 1
Reputation: 251
You can also add a PlainButtonStyle()
to your button to avoid iOS style behaviors.
Something like that with your example :
Button(action: {/* other code */}) {
PackageManagerRow(packageManager: packageManagersData[0])
}.buttonStyle(PlainButtonStyle())
I hope it will help you!
Upvotes: 16
Reputation: 69
You have to render the original image by adding .renderingMode(.original)
right after your image declaration.
Image("your_image_name")
.renderingMode(.original)
Upvotes: -1
Reputation: 6663
Another option is to not use a Button
wrapper, but instead use tapAction
directly on the Image to trigger your action when the image is pressed
Upvotes: 3
Reputation: 6223
HStack {
Button(action: {
print("Tapped")
}, label: {
Image("Logo").renderingMode(.original) // Add Rendering Mode
})
Text("Cydia")
}
Upvotes: 1
Reputation: 77661
I think this is from the rendering mode for the image you are using.
Where you have Image("Cydia logo")
(or whatever).
You should be setting the rendering mode like...
Image("Cydia Logo").renderingMode(.original)
Upvotes: 10