Skip to content

Instantly share code, notes, and snippets.

@waynedahlberg
Last active October 30, 2024 05:07
Show Gist options
  • Save waynedahlberg/bb8dc0276657b213c47d98ba42ea3769 to your computer and use it in GitHub Desktop.
Save waynedahlberg/bb8dc0276657b213c47d98ba42ea3769 to your computer and use it in GitHub Desktop.
Glass SwiftUI Button
//
// ContentView.swift
// Glass Button
//
// Created by Wayne Dahlberg on 9/25/24.
//
// IF YOU USE THIS, AND YOU ARE WELCOME TO... CREDIT ME AND REFER TO IT AS 'GLASSWARE' NOT 'GLASSMORPHISM'
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
NoiseBackground()
VStack {
Spacer()
HeaderView()
.padding(.bottom, 64)
}
}
.ignoresSafeArea(.all)
.persistentSystemOverlays(.hidden)
}
}
struct NoiseBackground: View {
var body: some View {
ZStack {
Color(#colorLiteral(red: 0.9058823529, green: 0.9058823529, blue: 0.9058823529, alpha: 1)) // #e7e7e7
Canvas { context, size in
context.addFilter(.alphaThreshold(min: 0.5, color: .black))
context.addFilter(.blur(radius: 8))
context.drawLayer { ctx in
for _ in 0..<100 {
let x = Double.random(in: 0...size.width)
let y = Double.random(in: 0...size.height)
let rect = CGRect(x: x, y: y, width: 1, height: 1)
ctx.fill(Path(rect), with: .color(.black.opacity(0.2)))
}
}
}
.opacity(0.2)
}
.ignoresSafeArea()
}
}
struct HeaderView: View {
@State private var isPressed = false
var body: some View {
HStack(spacing: 24) {
Button(action: {
// Login action
}) {
HStack(spacing: 8) {
LoginIcon()
Text("Login")
.font(.system(size: 14, weight: .semibold))
}
}
.buttonStyle(LinkButtonStyle())
Button(action: {
// Start trial action
}) {
HStack(spacing: 8) {
LockIcon()
Text("Upgrade to Pro")
.font(.system(size: 14, weight: .semibold))
}
.padding()
}
.buttonStyle(GlassButtonStyle(isPressed: $isPressed))
.shadow(color: Color.black.opacity(isPressed ? 0.15 : 0.5),
radius: isPressed ? 0 : 10,
x: 0,
y: isPressed ? 0 : 20)
.animation(.spring(response: 0.5, dampingFraction: 0.6, blendDuration: 0), value: isPressed)
}
}
}
struct LinkButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.foregroundColor(.black)
}
}
struct GlassButtonStyle: ButtonStyle {
@Binding var isPressed: Bool
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding(.vertical, 8)
.padding(.horizontal, 17)
.background(
ZStack {
Color.black.opacity(0.04)
RoundedRectangle(cornerRadius: 9999)
.strokeBorder(
LinearGradient(
gradient: Gradient(colors: [
Color.white.opacity(0.94),
Color(#colorLiteral(red: 0.4745098039, green: 0.4745098039, blue: 0.4745098039, alpha: 1)), // #797979
Color(#colorLiteral(red: 0.6431372549, green: 0.6431372549, blue: 0.6431372549, alpha: 1)), // #a4a4a4
Color.white
]),
startPoint: .top,
endPoint: .bottom
),
lineWidth: 1
)
}
)
.clipShape(RoundedRectangle(cornerRadius: 9999))
.shadow(color: Color.black.opacity(0.1), radius: 78, x: 0, y: 78)
.shadow(color: Color.black.opacity(0.07), radius: 50, x: 0, y: 50)
.shadow(color: Color.black.opacity(0.06), radius: 30, x: 0, y: 30)
.shadow(color: Color.black.opacity(0.04), radius: 16, x: 0, y: 16)
.shadow(color: Color.black.opacity(0.04), radius: 6, x: 0, y: 6)
.shadow(color: Color.black.opacity(0.02), radius: 2, x: 0, y: 2)
.scaleEffect(configuration.isPressed ? 0.9 : 1)
.animation(.easeInOut(duration: 0.2), value: configuration.isPressed)
.onChange(of: configuration.isPressed) { _, newValue in
isPressed = newValue
}
}
}
struct LoginIcon: View {
var body: some View {
Image(systemName: "person.crop.circle")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 18, height: 18)
}
}
struct LockIcon: View {
var body: some View {
Image(systemName: "lock.open")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 18, height: 18)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#Preview {
ContentView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment