Created
February 1, 2023 13:25
-
-
Save ArchieGoodwin/eacb0f16ad0fbc4df891c379ba67c280 to your computer and use it in GitHub Desktop.
KeyPad with support for long tap repeat digit
This file contains 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 | |
struct KeyPad: View { | |
@Binding var string: String | |
var action: () -> Void | |
var body: some View { | |
VStack { | |
KeyPadRow(keys: ["1", "2", "3"]) | |
KeyPadRow(keys: ["4", "5", "6"]) | |
KeyPadRow(keys: ["7", "8", "9"]) | |
KeyPadRow(keys: [NumberFormatter().decimalSeparator, "0", "<"]) | |
Spacer() | |
}.environment(\.keyPadButtonAction, self.keyWasPressed(_:)) | |
.padding(EdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20)) | |
} | |
private func keyWasPressed(_ key: String) { | |
let generator = UIImpactFeedbackGenerator(style: .medium) | |
generator.impactOccurred() | |
action() | |
switch key { | |
case NumberFormatter().decimalSeparator where string.contains(NumberFormatter().decimalSeparator): break | |
case NumberFormatter().decimalSeparator where string == "0": string += NumberFormatter().decimalSeparator | |
case "<": | |
if string.count == 1 { | |
string = "0" | |
} else { | |
string.removeLast() | |
if string.isEmpty { string = "0" } | |
} | |
case _ where string == "0": string = key | |
default: string += key | |
} | |
} | |
} | |
struct KeyPadRow: View { | |
var keys: [String] | |
var body: some View { | |
HStack { | |
ForEach(keys, id: \.self) { key in | |
KeyPadButton(key: key) | |
} | |
} | |
} | |
} | |
struct KeyPadButton: View { | |
var key: String | |
var body: some View { | |
Color.clear | |
.overlay(RoundedRectangle(cornerRadius: 12).foregroundColor(.clear)) | |
.overlay(Text(key).fontStyle(.title2).foregroundColor(.black)) | |
.modifier(TapAndLongPressModifier(tapAction: { | |
self.action(self.key) | |
}, longPressAction: { | |
// Log("tap and tap") | |
self.action(self.key) | |
})) | |
} | |
enum ActionKey: EnvironmentKey { | |
static var defaultValue: (String) -> Void { { _ in } } | |
} | |
@Environment(\.keyPadButtonAction) var action: (String) -> Void | |
} | |
extension EnvironmentValues { | |
var keyPadButtonAction: (String) -> Void { | |
get { self[KeyPadButton.ActionKey.self] } | |
set { self[KeyPadButton.ActionKey.self] = newValue } | |
} | |
} | |
struct TapAndLongPressModifier: ViewModifier { | |
@State private var canTap = true | |
@State private var pressId = 0 | |
let tapAction: () -> Void | |
let longPressAction: () -> Void | |
let timer = Timer.publish(every: 0.2, on: .main, in: .common).autoconnect() | |
@State var tick: Bool = false | |
@State var timerStarted: Bool = false | |
func body(content: Content) -> some View { | |
let tap = DragGesture(minimumDistance: 0) | |
.onChanged { _ in | |
if !timerStarted { | |
tapAction() | |
} | |
timerStarted = true | |
tick.toggle() | |
} | |
.onEnded { _ in | |
timerStarted = false | |
} | |
content | |
.gesture(tap) | |
.onReceive(timer) { _ in | |
if timerStarted { | |
longPressAction() | |
} | |
} | |
} | |
} | |
//Usage | |
KeyPad(string: $text, action: { | |
//action when key pressed | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment