amodrono
amodrono

Reputation: 2040

Avoid button styling its content in SwiftUI

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) without button styling

Inside the button (with button styling) 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

Answers (8)

itMaxence
itMaxence

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.

enter image description here

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

YanSte
YanSte

Reputation: 10839

Apply the style .plain to your button to avoid overlay color.

// Before
Button(...) 

with button styling

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

without button styling

Another solution is to custom the style with ButtonStyle

like: struct MyButtonStyle:ButtonStyle { }

Upvotes: 1

Paul B
Paul B

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

Cclleemm
Cclleemm

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

Fateh Khan
Fateh Khan

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

idolize
idolize

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

Jaydeep Vora
Jaydeep Vora

Reputation: 6223

HStack {
    Button(action: {
        print("Tapped")
     }, label: {
         Image("Logo").renderingMode(.original) // Add Rendering Mode
     })
    Text("Cydia")
}

Upvotes: 1

Fogmeister
Fogmeister

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

Related Questions