13

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)
        }
    }
}
2
  • 1
    Can you show the code you are using to create the button. Commented Jul 8, 2019 at 9:29
  • @Fogmeister of course, see my edit. Commented Jul 8, 2019 at 9:52

8 Answers 8

17

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!

Sign up to request clarification or add additional context in comments.

Comments

10

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)

3 Comments

When I add this method to my Image it gives me an error on the part where I set the image size: 'Double' is not convertible to 'Length?' (aka 'Optional<CGFloat>')
@iAlex11 Are you adding the rendering mode after adding the size?
Ohh ok thanks I see. Could you please explain why does this happen? Thanks and sorry to bother you.
9

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

Comments

3

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

Comments

2

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 { }

Comments

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

Comments

1

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.
        )
    }

Comments

-1

You have to render the original image by adding .renderingMode(.original) right after your image declaration.

Image("your_image_name")
    .renderingMode(.original)

3 Comments

Nice copy paste from the accepted answer!
mine don’t have spelling mistakes
@FatehKhan I reported this answer, you are being racist to new users and you should not copy paste answers, that is just embarrassing...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.