Is is possible in iOS to have an ascii capable decimal pad as the keyboard type for a UITextfield's keyboard type?

Viewed 1442

The app I'm writing supports multiple languages but there is 1 textfield where I want the user to write only ascii numbers (i.e. no arabic numbers) and decimal separators. I know it's possible to set a UITextfield's keyboardType but unfortunately there is a .decimalPad and asciiCapableNumberPad but neither of these suit my needs as asciiCapableNumberPad doesn't have the decimal separator button and decimalPad doesn't restrict it to ascii numbers.

Is it possible to have a asciiCapableDecimalPad? If not, what's the best way to restrict user input to ascii only numbers and decimal separators in a UITextField?

2 Answers

I didn't found any way force keyboard with ASCII number and decimal separator at once. On iPhone 8 when a user has only Arabic keyboard, for .decimalPad keyboard with only Eastern arabic numerals (٠١٢٣٤٥٦٧٨٩) will show, when has multiple keyboard (with eg. English keyboard), the user will have switch button for change different numerals. But this behavior is broken on iPhone X family for me, I think this is the bug on Apple side, the switch button doesn't exist.

I resolved this by implements method textField(_:shouldChangeCharactersIn:replacementString:) and inside this method I replace Eastern arabic numerals (Arabic-Indic?) to ASCII numerals (known also as Western arabic numberals) for validation entering characters during typing.

result = [result stringByReplacingOccurrencesOfString:@"٠" withString:@"0"];
result = [result stringByReplacingOccurrencesOfString:@"١" withString:@"1"];
result = [result stringByReplacingOccurrencesOfString:@"٢" withString:@"2"];
result = [result stringByReplacingOccurrencesOfString:@"٣" withString:@"3"];
result = [result stringByReplacingOccurrencesOfString:@"٤" withString:@"4"];
result = [result stringByReplacingOccurrencesOfString:@"٥" withString:@"5"];
result = [result stringByReplacingOccurrencesOfString:@"٦" withString:@"6"];
result = [result stringByReplacingOccurrencesOfString:@"٧" withString:@"7"];
result = [result stringByReplacingOccurrencesOfString:@"٨" withString:@"8"];
result = [result stringByReplacingOccurrencesOfString:@"٩" withString:@"9"];
result = [result stringByReplacingOccurrencesOfString:@"٫" withString:@"."];

I do the same in textFieldDidEndEditing:. There is the probability this step isn't needed, but I need to format number after losing focus also.

This fix is under testing and I'll let you know if there is any problem with this.

Swift-5 solution for all non-Latin string occurrences.

extension String {
    var containsNonEnglishNumbers: Bool {
        return !isEmpty && range(of: "[^0-9]", options: .regularExpression) == nil
    }

    var english: String {
        return self.applyingTransform(StringTransform.toLatin, reverse: false) ?? self
    }
}

Usage -

textField.addTarget(self, action: #selector(didChangeText(field:)), for: .editingChanged)

@objc func didChangeText(field: UITextField) {
    if ((field.text?.containsNonEnglishNumbers) != nil) {
        field.text = field.text?.english
    }
}
Related