Created
February 4, 2022 09:51
-
-
Save oliverepper/7007c665c52ba2498200f889d8518452 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
enum ButtonState { | |
case pressed | |
case notPressed | |
} | |
struct PressedModifier: ViewModifier { | |
@GestureState private var isPressed = false | |
let changeState: (ButtonState) -> Void | |
init(changeState: @escaping (ButtonState) -> Void) { | |
self.changeState = changeState | |
} | |
func body(content: Content) -> some View { | |
let drag = DragGesture(minimumDistance: 0) | |
.updating($isPressed) { value, gestureState, transition in | |
gestureState = true | |
} | |
return content | |
.gesture(drag) | |
.onChange(of: isPressed) { pressed in | |
if pressed { | |
self.changeState(.pressed) | |
} else { | |
self.changeState(.notPressed) | |
} | |
} | |
} | |
} | |
struct DialPadButton<T>: View where T: View { | |
@State private var pressed = false | |
var key: String | |
var caption: T? | |
var action: ((String, Bool) -> Void)? = { _, _ in } | |
var body: some View { | |
ZStack { | |
RoundedRectangle(cornerRadius: 12).stroke(Color.accentColor) | |
if caption == nil { | |
VStack { | |
Text(key) | |
} | |
} else { | |
caption | |
} | |
} | |
.contentShape(RoundedRectangle(cornerRadius: 12)) | |
.modifier(PressedModifier(changeState: { (state) in | |
print(state) | |
if state == .pressed { | |
pressed = true | |
} else { | |
withAnimation(.easeOut(duration: 0.1)) { | |
pressed = false | |
} | |
} | |
})) | |
.simultaneousGesture(LongPressGesture().onEnded { _ in | |
action?(key, true) | |
}) | |
.simultaneousGesture(TapGesture().onEnded { _ in | |
action?(key, false) | |
}) | |
.scaleEffect(pressed ? 0.9 : 1) | |
} | |
} | |
extension DialPadButton where T == VStack<Text> { | |
init(key: String, action: @escaping (String, Bool) -> Void) { | |
self.key = key | |
self.action = action | |
self.caption = VStack { | |
Text(key) | |
} | |
} | |
} | |
struct DialPad: View { | |
@Binding var number: String | |
var body: some View { | |
VStack { | |
row(keys: "1","2","3") | |
row(keys: "4","5","6") | |
row(keys: "7","8","9") | |
row(keys: "#","0","⌫") | |
} | |
} | |
private func row(keys: String...) -> some View { | |
HStack { | |
ForEach(keys, id:\.self) { key in | |
if key == "0" { | |
DialPadButton(key: key, caption: VStack { | |
Text(key) | |
Text("+").font(.subheadline) | |
}, action: press(key:longPress:)) | |
} else { | |
DialPadButton(key: key, action: press(key:longPress:)) | |
} | |
} | |
} | |
} | |
private func press(key: String, longPress: Bool) { | |
switch (key, longPress) { | |
case ("⌫", false): | |
if number.count > 0 { | |
number.removeLast() | |
} | |
case ("⌫", true): | |
number = "" | |
case ("0", false): | |
if number == "0" { | |
number = "+" | |
} else { | |
number += "0" | |
} | |
case ("0", true): | |
number += "+" | |
default: | |
number += key | |
} | |
} | |
} | |
struct DialView: View { | |
@State private var number = "" | |
@State private var name = "" | |
var body: some View { | |
VStack { | |
HStack { | |
Spacer() | |
VStack { | |
ZStack { | |
Text("+4915123595397").foregroundColor(.clear) | |
Text(number) | |
} | |
ZStack { | |
Text("Oliver Epper").foregroundColor(.clear) | |
Text(name) | |
}.font(.subheadline) | |
} | |
Spacer() | |
} | |
DialPad(number: $number) | |
.padding() | |
} | |
.font(.largeTitle) | |
.padding() | |
} | |
} | |
struct DialView_Previews: PreviewProvider { | |
static var previews: some View { | |
DialView() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment