Reputation: 2485
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.
Upvotes: 12
Views: 11302
Reputation: 1440
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))
}
}
Upvotes: 1
Reputation: 469
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()
)
}
}
Upvotes: 4
Reputation: 30496
It seems that no one has subclassed a
Button
in 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:
Upvotes: 36
Reputation: 1844
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())
Upvotes: 4
Reputation: 1256
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()
Upvotes: 0