'How to implement a reusable button with style, text and icon using SwiftUI?
I know how a custom ButtonStyle works. But I do want to have a fully reusable custom button.
Aka a button with Text and and Icon that has some styles applied.
I know how to achieve this using a ButtonStyle with a text property, but I think this is completely a misuse of button styles.
But I do not want to copy a Button with a large HStack as content all over my app.
What do you recommend in such use cases? It seems that no one has subclassed a Button in SwiftUI on the internet.
Solution 1:[1]
It seems that no one has subclassed a
Buttonin SwiftUI on the internet.
True. But that's because it's not possible - Button is a struct, so it can't be subclassed. Instead, what you can do is make a custom View.
struct CustomButton: View {
var text: String
var icon: Image
var clicked: (() -> Void) /// use closure for callback
var body: some View {
Button(action: clicked) { /// call the closure here
HStack {
Text(text) /// your text
icon /// your icon image
}
.foregroundColor(Color.green)
.padding()
.background(Color(.secondarySystemBackground))
.cornerRadius(16)
}
}
}
struct ContentView: View {
var body: some View {
CustomButton(
text: "Custom Button",
icon: Image(systemName: "plus")
) {
print("Clicked!")
}
}
}
Result:
Solution 2:[2]
You can use a ViewModifier.
The code below is a ViewModifier for a custom back button.
struct OverlayBackButton: ViewModifier {
@Environment(\.presentationMode) var presentation
func body(content: Content) -> some View {
content
.overlay(
Button(action: {
presentation.wrappedValue.dismiss()
}) {
Image(systemName: "chevron.backward") // set image here
.aspectRatio(contentMode: .fit)
.foregroundColor(.red)
Text("Back")
.foregroundColor(.red)
}
.padding()
,alignment: .topLeading
)
}
}
extension View {
func overlayBackButton() -> some View {
self.modifier(OverlayBackButton())
}
}
Then you can use the button like this
ZStack{
}
.overlayBackButton()
Solution 3:[3]
You can actually create Styles in Swift UI, for example ButtonStyle
Here is the sample code, you could copy-paste and try it
import SwiftUI
struct CustomButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
return configuration.label
.padding()
.background(Color.green)
.foregroundColor(Color.white)
.opacity(configuration.isPressed ? 0.7 : 1)
.scaleEffect(configuration.isPressed ? 0.8 : 1)
.animation(.easeInOut(duration: 0.2))
}
}
// USAGE:
Button(action: { }) {
Text("This is a custom button")
}
.buttonStyle(CustomButtonStyle())
Solution 4:[4]
struct DarkButton: View {
var buttonText: String = ""
var body: some View {
ZStack {
Text(buttonText)
.customDarkButtonStyle()
}
}
}
// MARK: - View Modifier to style our button -
/// If you need more customization add @State var
struct DarkButtonStyle: ViewModifier {
/// Background button color
var backgroundColor = Color.red
/// Foreground button color
var foregroundColor = Color.white
/// Button width
var width = 148
/// Button height
var height = 18
/// Button corner radius
var cornerRadius = 8
func body(content: Content) -> some View {
content
.foregroundColor(foregroundColor)
.font(/* Your font here */)
.frame(width: width, height: height)
.background(backgroundColor)
.cornerRadius(cornerRadius)
}
}
// MARK: - Cleaner way to call our custom ViewModifier -
extension View {
func customDarkButtonStyle() -> some View {
ModifiedContent(
content: self,
modifier: DarkButtonStyle()
)
}
}
Solution 5:[5]
You can of course fully customize the button with ButtonStyle. The makeBody just has to return a view, and configuration.label is just a label. No magic involved. Just wrap the label anyway you see fit. You can e.g. do like this to add an icon to the button:
struct CustomButtonStyle: ButtonStyle {
func makeBody(configuration: Self.Configuration) -> some View {
return
HStack {
Image("imageName")
configuration.label
}
.padding()
.background(Color.green)
.foregroundColor(Color.white)
.opacity(configuration.isPressed ? 0.7 : 1)
.scaleEffect(configuration.isPressed ? 0.8 : 1)
.animation(.easeInOut(duration: 0.2))
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | aheze |
| Solution 2 | Taeeun Kim |
| Solution 3 | minchaej |
| Solution 4 | manubrio |
| Solution 5 | Johannes |

