Custom SwiftUI Button with “On Pressed” configuration in iOS 13

Eduardo Domene Junior
Geek Culture
Published in
2 min readFeb 5, 2023
Photo by Yuri Catalano on Unsplash

Creating buttons in SwiftUI can be quite straightforward in iOS 15. You just need to add the following code to have a purple button that changes its color once pressed.

Button {
// action
} label: {
Text("Title")
.frame(maxWidth: .infinity)
}
.buttonStyle(.borderedProminent)
.tint(.purple)

On iOS 13, however, this is not the case. Both .borderedProminent and .tint are only available since iOS 15. So, how can we create a similar button and even customize it a bit more?

The following image is what we will achieve; a button that can take an optional Image, a title, an action and a custom color once pressed:

The solution involves listening to the isEnabled environment variable and using a custom ButtonStyle, which is updated in case the variable changes. The colors used for the different states of the button, like “on pressed”, enabled and disabled can be found in the ButtonStyle also. Here is the complete code:

public struct CustomButton: View {
private let text: String
private let icon: Image?
private let action: (() -> Void)

// Tracks the enabled state of the view.
// Check https://developer.apple.com/documentation/swiftui/environmentvalues/isenabled
@Environment(\.isEnabled) var isEnabled

public var body: some View {
Button {
action()
} label: {
HStack {
icon
Text(text).font(.body)
}
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.padding(8)
}
.buttonStyle(CustomButtonStyle(isEnabled: isEnabled))
}

public init(_ text: String,
@ViewBuilder icon: () -> Image? = { nil },
action: @escaping() -> Void) {
self.icon = icon()
self.text = text
self.action = action
}
}

private struct CustomButtonStyle: ButtonStyle {
let isEnabled: Bool

@ViewBuilder
func makeBody(configuration: Configuration) -> some View {
let backgroundColor = isEnabled ? Color.purple : Color(UIColor.lightGray)
let pressedColor = Color.red
let background = configuration.isPressed ? pressedColor : backgroundColor

configuration.label
.foregroundColor(.white)
.background(background)
.cornerRadius(8)
}
}

--

--