mirror of
https://github.com/jordansinger/SwiftUI-Kit.git
synced 2026-03-03 18:23:32 +01:00
* Added Widget * Fixed tvOS not compiling * Added Button Modifiers Sheet Ability to view sheet in button section that displays all the modifiers on a button and their impact on the buttons when they are changed
196 lines
7.3 KiB
Swift
196 lines
7.3 KiB
Swift
//
|
|
// ButtonModifiers.swift
|
|
// SwiftUI Kit iOS
|
|
//
|
|
// Created by Thomas Braun on 8/4/20.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
struct ButtonStyleParams {
|
|
let scale: Double
|
|
let rotation: Double
|
|
let blur: Double
|
|
let color: Color
|
|
let unpressedColor: Color
|
|
let animate: Bool
|
|
let response: Double
|
|
let damping: Double
|
|
let duration: Double
|
|
}
|
|
|
|
let DEFAULT_SCALE: Double = 0.85
|
|
let DEFAULT_ROTATION: Double = 0
|
|
let DEFAULT_BLUR: Double = 0
|
|
let DEFAULT_COLOR: Color = Color.primary.opacity(0.75)
|
|
let DEFAULT_ANIMATE: Bool = true
|
|
let DEFAULT_RESPONSE: Double = 0.35
|
|
let DEFAULT_DAMPING: Double = 0.35
|
|
let DEFAULT_DURATION: Double = 1
|
|
let DEFAULT_BUTTONCOLOR: Color = Color.black
|
|
let DEFAULT_TEXTCOLOR: Color = Color.white
|
|
|
|
struct ButtonModifiers: View {
|
|
@State private var scale = DEFAULT_SCALE
|
|
@State private var rotation = DEFAULT_ROTATION
|
|
@State private var blur = DEFAULT_BLUR
|
|
@State private var color = DEFAULT_COLOR
|
|
@State private var buttonColor = DEFAULT_BUTTONCOLOR
|
|
@State private var textColor = DEFAULT_TEXTCOLOR
|
|
@State private var animate = DEFAULT_ANIMATE
|
|
@State private var response = DEFAULT_RESPONSE
|
|
@State private var damping = DEFAULT_DAMPING
|
|
@State private var duration = DEFAULT_DURATION
|
|
|
|
var body: some View {
|
|
VStack(spacing: 20) {
|
|
Spacer()
|
|
HStack(spacing: 30) {
|
|
Button(action: { }) {
|
|
Text("tap here")
|
|
.testButtonStyle(textColor: textColor)
|
|
}
|
|
.pressableButton(style: getParams())
|
|
.foregroundColor(buttonColor)
|
|
Button(action: { }) {
|
|
Text("or here")
|
|
.font(Font.body.bold())
|
|
.padding()
|
|
}
|
|
.pressableButton(style: getParams(), drawBackground: false)
|
|
Button(action: { }) {
|
|
Image(systemName: "star.fill")
|
|
.testButtonStyle(textColor: textColor)
|
|
}
|
|
.pressableButton(style: getParams())
|
|
.foregroundColor(buttonColor)
|
|
}
|
|
.zIndex(1)
|
|
ScrollView {
|
|
ScrollViewReader { reader in
|
|
VStack(alignment: .leading) {
|
|
Group {
|
|
Text("Scale Effect: \(scale * 100, specifier: "%.0f")%")
|
|
.font(Font.body.bold())
|
|
Slider(value: $scale, in: 0.05...2, step: 0.05)
|
|
Text("Rotation Effect: \(rotation, specifier: "%.0f") degrees")
|
|
.font(Font.body.bold())
|
|
Slider(value: $rotation, in: -360...360, step: 5)
|
|
Text("Blur Radius: \(blur, specifier: "%.1f")")
|
|
.font(Font.body.bold())
|
|
Slider(value: $blur, in: 0...15, step: 0.5)
|
|
}
|
|
Divider()
|
|
Group {
|
|
ColorPicker("Button Color", selection: $buttonColor)
|
|
.font(Font.body.bold())
|
|
.padding(.vertical)
|
|
ColorPicker("Button Text Color", selection: $textColor)
|
|
.font(Font.body.bold())
|
|
.padding(.vertical)
|
|
ColorPicker("Tap Color", selection: $color)
|
|
.font(Font.body.bold())
|
|
.padding(.vertical)
|
|
}
|
|
Divider()
|
|
Toggle("Animate", isOn: $animate.animation())
|
|
.font(Font.body.bold())
|
|
.toggleStyle(SwitchToggleStyle(tint: DEFAULT_COLOR))
|
|
.padding(.vertical)
|
|
if animate {
|
|
Text("Spring Stiffness: \(response, specifier: "%.2f")")
|
|
.font(Font.body.bold())
|
|
Slider(value: $response, in: 0...1, step: 0.05)
|
|
Text("(low for fast, high for slow)")
|
|
.font(Font.caption.bold())
|
|
.padding(.bottom, 10)
|
|
Text("Spring Damping: \(damping, specifier: "%.2f")")
|
|
.font(Font.body.bold())
|
|
Slider(value: $damping, in: 0.05...1, step: 0.05)
|
|
Text("(low for large bounce, high for small bounce)")
|
|
.font(Font.caption.bold())
|
|
}
|
|
}
|
|
.accentColor(DEFAULT_COLOR)
|
|
.padding(30)
|
|
.background(RoundedRectangle(cornerRadius: 30, style: .continuous)
|
|
.foregroundColor(Color.primary.opacity(0.05)))
|
|
.padding()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func getParams() -> ButtonStyleParams {
|
|
return ButtonStyleParams(scale: scale,
|
|
rotation: rotation,
|
|
blur: blur,
|
|
color: color,
|
|
unpressedColor: buttonColor,
|
|
animate: animate,
|
|
response: response,
|
|
damping: damping,
|
|
duration: duration)
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
extension Double {
|
|
func rounded(toPlaces places:Int) -> Double {
|
|
let divisor = pow(10.0, Double(places))
|
|
return (self * divisor).rounded() / divisor
|
|
}
|
|
}
|
|
|
|
// MARK: - Button
|
|
|
|
struct TestButton: ViewModifier {
|
|
|
|
let textColor: Color
|
|
|
|
func body(content: Content) -> some View {
|
|
content
|
|
.font(Font.body.bold())
|
|
.imageScale(.large)
|
|
.padding()
|
|
.foregroundColor(textColor)
|
|
// .colorInvert()
|
|
}
|
|
}
|
|
|
|
extension Image {
|
|
func testButtonStyle(textColor: Color) -> some View {
|
|
self.modifier(TestButton(textColor: textColor))
|
|
}
|
|
}
|
|
|
|
extension Text {
|
|
func testButtonStyle(textColor: Color) -> some View {
|
|
self.modifier(TestButton(textColor: textColor))
|
|
}
|
|
}
|
|
|
|
struct ButtonPressedStyle: ButtonStyle {
|
|
var style: ButtonStyleParams
|
|
var drawBackground: Bool
|
|
|
|
func makeBody(configuration: Self.Configuration) -> some View {
|
|
configuration.label
|
|
.background(Capsule()
|
|
.foregroundColor(configuration.isPressed ? style.color : style.unpressedColor)
|
|
.opacity(drawBackground ? 1 : 0))
|
|
.scaleEffect(configuration.isPressed ? CGFloat(style.scale) : 1.0)
|
|
.rotationEffect(.degrees(configuration.isPressed ? style.rotation : 0))
|
|
.blur(radius: configuration.isPressed ? CGFloat(style.blur) : 0)
|
|
.animation(style.animate ? Animation.spring(response: style.response, dampingFraction: style.damping, blendDuration: style.duration) : .none)
|
|
}
|
|
}
|
|
|
|
extension Button {
|
|
func pressableButton(style: ButtonStyleParams, drawBackground: Bool = true) -> some View {
|
|
self.buttonStyle(ButtonPressedStyle(style: style, drawBackground: drawBackground))
|
|
}
|
|
}
|