Customizing SwiftUI Buttons With ButtonStyle

Quinton Pryce
1v1Me Blog
Published in
2 min readDec 19, 2022

SwiftUI’s ButtonStyle can be a really powerful configuration tool to make quick & concise buttons for your app.

ButtonStyles let us define a set of modifiers to apply to a button in one line (theming, animations, haptics, etc.).

Theming With ButtonStyles

One of the ButtonStyles at 1v1Me is a Pill. We have written custom initializers for frequently used backgroundColor and titleColor combinations.

struct Pill: ButtonStyle {
let backgroundColor: Color
let titleColor: Color

static var destructive: Pill {
return Pill(backgroundColor: .red, titleColor: .white)
}

func makeBody(configuration: Configuration) -> some View {
configuration.label
.font(.system(size: 16, weight: .bold))
.padding(.horizontal, 16)
.background(backgroundColor)
.foregroundColor(titleColor)
.frame(maxWidth: .infinity)
.frame(height: 48)
.clipShape(Capsule())
}
}

Button("Press Me!", action: {
print("Hello, World!")
})
.buttonStyle(Pill.destructive)

Ensure Tapability

Not all buttons are going to have content from edge-to-edge. Our event card is a custom view inside a button with some empty areas which are not tappable by default:

Buttons are not tappable by default if the views do not extend all the way to the sides. Any area that is black in our event card is not tappable without additional customization.

To fix this we can add a content shape to our ButtonStyle to ensure that the entire button is tappable.

struct Tappable: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.contentShape(Rectangle())
}
}

Adding Touch Animations & Haptics To Buttons

If you want to add more familiarity to your buttons & bring a sense of touch you can add animations.

struct ScaleOnTap: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.scaleEffect(configuration.isPressed ? 0.95 : 1)
}
}

Adding Haptics To Buttons

Haptics are a powerful way to bring your app into the physical world.

The simplest way to add Haptics to your buttons within your ButtonStyle is to lean on the animations that you might have already set.

struct ScaleOnTap: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.scaleEffect(
configuration.isPressed ?
{ Global.haptics.interaction(); return 0.95 }() : 1
)
}
}

Unfortunately, SwiftUI hasn’t made any hooks available for button taps in ButtonStyles besides simultaneousGesture which unfortunately doesn’t work when applied to the label of the Button.

Other than this shoehorn we added to get haptics in our ButtonStyles, you can go with a custom button with tap gestures to get the same result.

Bonus Haptics Interaction Example

An example of what a haptics interaction might look like.

--

--

Quinton Pryce
1v1Me Blog

iOS Developer | Camper | Believer in Resilience