Skip to content

Instantly share code, notes, and snippets.

@juanjovn
Created April 22, 2024 18:47
Show Gist options
  • Save juanjovn/297a68dc555f5c799634c59f5054f8dd to your computer and use it in GitHub Desktop.
Save juanjovn/297a68dc555f5c799634c59f5054f8dd to your computer and use it in GitHub Desktop.
SwiftUI buttons in a Neubrutalism style
//
// 🌯⚡️ UI Components included in WrapFast SwiftUI Starter Kit: https://WrapFa.st
//
import SwiftUI
struct BrutoButtonStyle: ButtonStyle {
@ViewBuilder
func makeBody(configuration: Configuration) -> some View {
configuration.label
}
}
struct BrutoButton: View {
// Public
@Binding var text: String
@State var backgroundColor: Color
@State var accentColor: Color
@State var shadowOpacity: CGFloat
@State var strokeWidth: CGFloat
var action: () -> Void
// Private
private let offset: CGFloat = 4
@State private var tapped = false
init(text: Binding<String>,
backgroundColor: Color = .customBackground,
accentColor: Color = .primary,
shadowOpacity: CGFloat = 1,
strokeWidth: CGFloat = 6,
action: @escaping () -> Void = {}) {
_text = text
self.backgroundColor = backgroundColor
self.accentColor = accentColor
self.shadowOpacity = shadowOpacity
self.strokeWidth = strokeWidth
self.action = action
}
var body: some View {
Button {
action()
} label: {
Rectangle()
.background(backgroundColor).opacity(shadowOpacity)
.cornerRadius(5)
.offset(x: tapped ? 0 : offset, y: tapped ? 0 : offset)
.overlay(
ZStack {
Rectangle()
.stroke(accentColor, lineWidth: strokeWidth)
.background(backgroundColor)
.cornerRadius(5)
Text(text)
.foregroundColor(accentColor)
}
)
.offset(x: tapped ? offset : 0, y: tapped ? offset : 0)
}
.buttonStyle(BrutoButtonStyle())
._onButtonGesture { _ in
Haptic.shared.selectionChanged()
tapped.toggle()
} perform: {
Haptic.shared.selectionChanged()
}
}
}
struct BrutoButton_Previews: PreviewProvider {
static var previews: some View {
BrutoButton(text: .constant("33"),
backgroundColor: .white,
strokeWidth: 8)
.frame(maxWidth: 80, maxHeight: 80)
.font(.system(.title, design: .rounded, weight: .black))
}
}
struct BrutoImageButton: View {
// Public
@State var image: Image
@State var imagePrimaryColor: Color
@State var imageSecondaryColor: Color
@Binding var text: String
@State var backgroundColor: Color
@State var accentColor: Color
@State var shadowOpacity: CGFloat
@State var strokeWidth: CGFloat
var action: () -> Void
// Private
private let offset: CGFloat = 4
@State private var tapped = false
init(image: Image,
imagePrimaryColor: Color = .primary,
imageSecondaryColor: Color = .secondary,
text: Binding<String>,
backgroundColor: Color = .customBackground,
accentColor: Color = .primary,
shadowOpacity: CGFloat = 1,
strokeWidth: CGFloat = 6,
action: @escaping () -> Void = {}) {
self.image = image
self.imagePrimaryColor = imagePrimaryColor
self.imageSecondaryColor = imageSecondaryColor
_text = text
self.backgroundColor = backgroundColor
self.accentColor = accentColor
self.shadowOpacity = shadowOpacity
self.strokeWidth = strokeWidth
self.action = action
}
var body: some View {
Button {
action()
} label: {
Rectangle()
.background(backgroundColor).opacity(shadowOpacity)
.cornerRadius(5)
.offset(x: tapped ? 0 : offset, y: tapped ? 0 : offset)
.overlay(
ZStack {
Rectangle()
.stroke(accentColor, lineWidth: strokeWidth)
.background(backgroundColor)
.cornerRadius(5)
HStack(spacing: 8) {
image
.resizable()
.scaledToFit()
.frame(maxWidth: 30, maxHeight: 30)
.fontWeight(.medium)
.foregroundStyle(imagePrimaryColor, imageSecondaryColor)
Text(text)
.foregroundColor(accentColor)
}
.padding(.horizontal)
}
)
.offset(x: tapped ? offset : 0, y: tapped ? offset : 0)
}
.buttonStyle(BrutoButtonStyle())
._onButtonGesture { _ in
Haptic.shared.selectionChanged()
tapped.toggle()
} perform: {
Haptic.shared.selectionChanged()
}
}
}
#Preview {
BrutoImageButton(image: .init(systemName: "apple.logo"), text: .constant("Button with Image"))
.frame(width: 250, height: 50)
.font(.system(.title3, design: .rounded, weight: .bold))
}
struct BrutoCircleButton: View {
// Public
@Binding var text: String?
@Binding var image: Image?
@State var backgroundColor: Color
@State var accentColor: Color
@State var shadowOpacity: CGFloat
@State var strokeWidth: CGFloat
var action: () -> Void
// Private
private let offset: CGFloat = 5
@State private var tapped = false
init(text: Binding<String?> = .constant(nil),
image: Binding<Image?> = .constant(nil),
backgroundColor: Color = .customBackground,
accentColor: Color = .primary,
shadowOpacity: CGFloat = 1,
strokeWidth: CGFloat = 5,
action: @escaping () -> Void = {}) {
_text = text
_image = image
self.backgroundColor = backgroundColor
self.accentColor = accentColor
self.shadowOpacity = shadowOpacity
self.strokeWidth = strokeWidth
self.action = action
}
var body: some View {
Button {
action()
} label: {
Circle()
.fill(accentColor.opacity(shadowOpacity))
.offset(x: tapped ? 0 : offset, y: tapped ? 0 : offset)
.overlay(
ZStack {
Circle()
.fill(backgroundColor)
.overlay{
Circle()
.stroke(accentColor, lineWidth: strokeWidth)
}
if let image {
image
.fontWeight(.medium)
} else if let text {
Text(text)
.foregroundColor(accentColor)
}
}
)
.offset(x: tapped ? offset : 0, y: tapped ? offset : 0)
}
.buttonStyle(BrutoButtonStyle())
._onButtonGesture { _ in
Haptic.shared.selectionChanged()
tapped.toggle()
} perform: {
Haptic.shared.selectionChanged()
}
}
}
#Preview {
BrutoCircleButton(text: .constant("OK"))
.frame(width: 80)
.font(.system(size: 30))
.fontWeight(.black)
}
@juanjovn
Copy link
Author

🌯⚡️This and more UI components included in WrapFast SwiftUI Starter Kit: https://WrapFa.st

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment