Skip to content

Instantly share code, notes, and snippets.

@mattyoung
Last active December 29, 2022 22:27
Show Gist options
  • Save mattyoung/4dacf36fa209c4d808e1f27d379c1a41 to your computer and use it in GitHub Desktop.
Save mattyoung/4dacf36fa209c4d808e1f27d379c1a41 to your computer and use it in GitHub Desktop.
import SwiftUI
//import Combine
struct NumbersOnlyViewModifier: ViewModifier {
@Binding var text: String
var includeDecimal: Bool
func body(content: Content) -> some View {
content
.keyboardType(includeDecimal ? .decimalPad : .numberPad)
.onChange(of: text) { newValue in
if includeDecimal {
do {
let fixup: String
if let lastChar = newValue.last, !lastChar.isNumber { // we have a decimal point at the end?
fixup = String(lastChar)
} else {
fixup = ""
}
let parsedResult = try Double(newValue, format: .number).formatted(.number.grouping(.never)) + fixup
if newValue != parsedResult {
text = String(newValue.dropLast())
}
} catch {
text = String(newValue.dropLast())
}
} else {
do {
let sanitizedNewValue = String(newValue.dropFirst(newValue.prefix(while: { $0 == "0" }).count))
let parsedResult = try Int(sanitizedNewValue, format: .number).formatted(.number.grouping(.never))
if sanitizedNewValue != parsedResult {
text = String(newValue.dropLast())
} else if newValue != sanitizedNewValue {
text = sanitizedNewValue
}
} catch {
text = String(newValue.dropLast())
}
}
}
}
}
extension View {
func numberOnly(_ text: Binding<String>, includeDecimal: Bool = false) -> some View {
modifier(NumbersOnlyViewModifier(text: text, includeDecimal: includeDecimal))
}
}
struct NumericTextFieldDemo: View {
@State private var anInteger = 0
@State private var aDecimal = 0.0
@State private var textInt = "0"
@State private var textDec = "0."
var body: some View {
VStack {
// this allows for only Int values, but the problem is you can enter anything, not number only
// how to restrict this to number only?
// with a String value TextField, you can monitor the input and not allow non-number
// but here we have nothing to monitor.
TextField("Enter a integer", value: $anInteger, format: .number)
.textFieldStyle(.roundedBorder)
.keyboardType(.numberPad)
TextField("Enter a integer", value: $aDecimal, format: .number)
.textFieldStyle(.roundedBorder)
.keyboardType(.decimalPad)
TextField("Number only!", text: $textInt)
.numberOnly($textInt)
TextField("Number and decimal only!", text: $textDec)
.numberOnly($textDec, includeDecimal: true)
}
}
}
struct NumericTextFieldDemo_Previews: PreviewProvider {
static var previews: some View {
NumericTextFieldDemo()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment