Skip to content

Instantly share code, notes, and snippets.

@jmcd
Last active April 22, 2023 13:55
Show Gist options
  • Save jmcd/cf71979f9da8997486c584154c659700 to your computer and use it in GitHub Desktop.
Save jmcd/cf71979f9da8997486c584154c659700 to your computer and use it in GitHub Desktop.
SwiftUI ButtonStyle that mimics classic beveled buttons from NeXTSTEP and Windows 95
import SwiftUI
extension Color {
static var redmondBackground = Color(white: 0.78)
static var redmondShadow = Color(white: 0.55)
}
extension Font {
static var redmondLabel = Font(UIFont(name: "MicrosoftSansSerif", size: UIFont.labelFontSize)!)
}
struct RedmondButtonStyle: ButtonStyle {
@State var lineWidth: CGFloat = 2
func makeBody(configuration: Self.Configuration) -> some View {
let offset = configuration.isPressed ? lineWidth : 0
return configuration.label
.font(.redmondLabel)
.offset(x: offset, y: offset).animation(nil)
.background(
ZStack {
Corner(style: configuration.isPressed ? .topLeft : .bottomRight).stroke(Color.redmondShadow, lineWidth: lineWidth).padding(lineWidth)
Corner(style: configuration.isPressed ? .bottomRight : .topLeft).stroke(Color.white, lineWidth: lineWidth)
Corner(style: configuration.isPressed ? .topLeft : .bottomRight).stroke(Color.black, lineWidth: lineWidth)
}
.animation(nil)
)
}
}
struct Corner: Shape {
enum Style { case topLeft, bottomRight }
@State var style: Style
func path(in rect: CGRect) -> Path {
Path { path in
path.move(to: CGPoint(x: 0, y: rect.size.height))
path.addLine(to: style == .topLeft ? .zero : CGPoint(x: rect.size.width, y: rect.size.height))
path.addLine(to: CGPoint(x: rect.size.width, y: 0))
}
}
}
struct DemoView: View {
private func button(text: String, action: @escaping () -> ()) -> some View {
button(content: Text(text).frame(width: 90, height: 35), action: action)
}
private func button(systemImageName: String, action: @escaping () -> ()) -> some View {
button(content:
Image(systemName: systemImageName)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 25, height: 25)
.padding(8),
action: action)
}
private func button<T: View>(content: T, action: @escaping () -> ()) -> some View {
Button(action: action) {
content
}.buttonStyle(RedmondButtonStyle())
}
var body: some View {
VStack(alignment: .leading, spacing: 20) {
HStack {
button(systemImageName: "doc.text") { print("doc") }
button(systemImageName: "folder") {}
button(systemImageName: "calendar") {}
button(systemImageName: "person") {}
button(systemImageName: "trash") {}
Spacer()
}
HStack {
button(text: "Cancel") {}
button(text: "OK") { print("ok") }
Spacer()
}
Spacer()
}
.padding()
.background(Color.redmondBackground)
}
}
struct DemoView_Previews: PreviewProvider {
static var previews: some View {
DemoView()
}
}
@lgrachov
Copy link

Not working.

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