Skip to content

Instantly share code, notes, and snippets.

@ArchieGoodwin
Created February 1, 2023 13:25
Show Gist options
  • Save ArchieGoodwin/eacb0f16ad0fbc4df891c379ba67c280 to your computer and use it in GitHub Desktop.
Save ArchieGoodwin/eacb0f16ad0fbc4df891c379ba67c280 to your computer and use it in GitHub Desktop.
KeyPad with support for long tap repeat digit
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