如何限制 UITextField 在 Swift 中只接受数字?
Posted
技术标签:
【中文标题】如何限制 UITextField 在 Swift 中只接受数字?【英文标题】:How to restrict UITextField to take only numbers in Swift? 【发布时间】:2015-06-22 06:06:12 【问题描述】:我希望用户只在UITextField
中输入数值。在 iPhone 上我们可以显示数字键盘,但在 iPad 上用户可以切换到任何键盘。
有没有办法限制用户在UITextField
中只输入数值?
【问题讨论】:
您必须更改输入的文本。 是的,但是在 ipad 中,即使我们设置了数字键盘,用户也可以输入字母 修改文字是什么意思? 看到这个***.com/questions/12944789/… ***.com/questions/26919854/… 【参考方案1】:swift 3.0及以上的解决方案
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
let allowedCharacters = CharacterSet.decimalDigits
let characterSet = CharacterSet(charactersIn: string)
return allowedCharacters.isSuperset(of: characterSet)
【讨论】:
你的视图控制器应该符合UITextFieldDelegate
,在viewDidLoad中放入yourNumbersTextField.delegate = self
什么是范围?
你为什么没有提到 UITextFieldDelegate??
@user924 范围由 UITextField 委托方法返回
@user924 提到 UITextFieldDelegate 是基本要求【参考方案2】:
这是我的 2 美分。 (仅在 Swift 2 上测试)
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
let aSet = NSCharacterSet(charactersInString:"0123456789").invertedSet
let compSepByCharInSet = string.componentsSeparatedByCharactersInSet(aSet)
let numberFiltered = compSepByCharInSet.joinWithSeparator("")
return string == numberFiltered
这只是更严格一点。也没有小数点。
希望对你有帮助:)
PS:我还以为你照顾了委托人。
更新:Swift 3.0:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
let aSet = NSCharacterSet(charactersIn:"0123456789").inverted
let compSepByCharInSet = string.components(separatedBy: aSet)
let numberFiltered = compSepByCharInSet.joined(separator: "")
return string == numberFiltered
【讨论】:
如何限制 UITextfield 只接收数字并限制 6 到 8 之间的数字数量? 您可以将aSet
设置为CharacterSet.decimalDigits.invertedSet
非常适合我的需求。谢谢。
你为什么没有提到 UITextFieldDelegate??
您还应该添加对text == ""
的检查,以便用户可以向后删除文本。【参考方案3】:
在 swift 4.1 和 Xcode 9.4.1 中
将 UITextFieldDelegate 添加到您的班级
class YourViewController: UIViewController, UITextFieldDelegate
然后在你的 viewDidLoad()
中编写这段代码mobileNoTF.delegate = self
编写此文本字段委托函数
//MARK - UITextField Delegates
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
//For mobile numer validation
if textField == mobileNoTF
let allowedCharacters = CharacterSet(charactersIn:"+0123456789 ")//Here change this characters based on your requirement
let characterSet = CharacterSet(charactersIn: string)
return allowedCharacters.isSuperset(of: characterSet)
return true
【讨论】:
我该如何修复Binary operator '==' cannot be applied to operands of type 'UITextField' and '() -> ()'
@ios,它是如何工作的?我已经添加了所有内容,但我仍然可以输入任何内容。该字段允许任何字符,并且不会触发 textField 函数。【参考方案4】:
斯威夫特 2.0
只允许数字和一个“。” uitextfield 中的小数。
func textField(textField: UITextField,shouldChangeCharactersInRange range: NSRange,replacementString string: String) -> Bool
let newCharacters = NSCharacterSet(charactersInString: string)
let boolIsNumber = NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(newCharacters)
if boolIsNumber == true
return true
else
if string == "."
let countdots = textField.text!.componentsSeparatedByString(".").count - 1
if countdots == 0
return true
else
if countdots > 0 && string == "."
return false
else
return true
else
return false
【讨论】:
谢谢 - 太好了(我一直在寻找只允许 1 个“.”的解决方案)【参考方案5】:仅限 iPhone 的解决方案
在您从中获取这些值的任何 UITextField 中,您都可以指定当有人在文本字段内触摸时想要显示的键盘类型。
例如纯数字键盘。
喜欢这个截图:
iPad
iPad 不支持数字键盘,因此您可以选择不支持 iPad、验证提交后的字段,或者按照此处的其他建议之一在 iPad 上运行时创建相同的行为。
【讨论】:
这不能回答问题。即使使用数字键盘,iOS 也允许用户将非数字值粘贴到 UITextField 或允许 iPad 将键盘从数字切换。 这是这个问题的简单答案!!没有正确答案!我知道! 这不是问题的任何答案,既不简单也不恰当。问题不是询问如何更改键盘类型。问题是询问如何限制输入。这些是不同的。 问题是:如何限制 UITextField 在 Swift 中只取数字?所以当你的键盘类型是数字键盘时,显然满足要求。 OP 明确要求提供另一种解决方案,而不是更改键盘类型。 “在 iPhone 上我们可以显示数字键盘,但在 iPad 上用户可以切换到任何键盘。”【参考方案6】:在 Swift 3 中接受带有单个 (.) 点的文本字段中的十进制值
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
let inverseSet = NSCharacterSet(charactersIn:"0123456789").inverted
let components = string.components(separatedBy: inverseSet)
let filtered = components.joined(separator: "")
if filtered == string
return true
else
if string == "."
let countdots = textField.text!.components(separatedBy:".").count - 1
if countdots == 0
return true
else
if countdots > 0 && string == "."
return false
else
return true
else
return false
【讨论】:
这是我唯一可以工作的(限制为一位小数),太棒了! 实际上我对其进行了修改以允许使用一个逗号(根据 FR) 请注意,并非所有语言环境都使用“.”作为小数分隔符。您可能想改用 Locale.current.decimalSeparator。【参考方案7】:func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
// return true if the replacementString only contains numeric characters
let digits = NSCharacterSet.decimalDigitCharacterSet()
for c in string
if !digits.characterIsMember(c)
return false
return true
即使用户切换键盘或尝试将非数字字符串粘贴到文本字段中,此解决方案也可以工作。
确保设置相应文本字段的delegate
属性。
【讨论】:
使用[string intValue]
如上一个答案中所建议的将不起作用,因为即使string
包含非数字字符,该属性也可能为真(非零)。根据文档,intValue
仅在“字符串不以数字的有效十进制文本表示开头”时为 0。【参考方案8】:
使用数字格式化程序
Swift 4.x
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
let s = NSString(string: textField.text ?? "").replacingCharacters(in: range, with: string)
guard !s.isEmpty else return true
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .none
return numberFormatter.number(from: s)?.intValue != nil
【讨论】:
谢谢!这个比许多其他的要好,因为它允许小数但不能任意使用小数。【参考方案9】:这是一个简单的解决方案,您需要在控制器中将“编辑更改”事件连接到此方法
斯威夫特 4
@IBAction func valueChanged(_ sender: UITextField)
if let last = sender.text?.last
let zero: Character = "0"
let num: Int = Int(UnicodeScalar(String(last))!.value - UnicodeScalar(String(zero))!.value)
if (num < 0 || num > 9)
//remove the last character as it is invalid
sender.text?.removeLast()
【讨论】:
如果代理已经被 Rx 使用,这是一个很好的解决方案。 如果我添加空格或符号会崩溃【参考方案10】:像这样扩展你的视图控制器:
class MyViewController: UIViewController, UITextFieldDelegate
在 viewDidLoad 函数中,像这样扩展到您的文本字段:
myTextField.delegate = self
然后使用下面的函数:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
let isNumber = CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: string))
let withDecimal = (
string == NumberFormatter().decimalSeparator &&
textField.text?.contains(string) == false
)
return isNumber || withDecimal
这将确保用户只能输入十进制数字。
斯威夫特 4 + 只接受号码 并接受一个分隔符
【讨论】:
【参考方案11】:第一个你必须继承你自己的 UITextFieldDelegate 类 类
class ViewController: UIViewController, UITextFieldDelegate
第二次添加 IBOutlet
@IBOutlet weak var firstName: UITextField!
第三你必须确保这个对象正在使用
override func viewDidLoad()
super.viewDidLoad()
firstName.delegate = self
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
if textField == firstName
let allowedCharacters = "1234567890"
let allowedCharacterSet = CharacterSet(charactersIn: allowedCharacters)
let typedCharacterSet = CharacterSet(charactersIn: string)
let alphabet = allowedCharacterSet.isSuperset(of: typedCharacterSet)
return alphabet
【讨论】:
【参考方案12】://除了这些,您只需将键盘更改为数字类型
yourtextfield.keyboardType = UIKeyboardType.numberPad
【讨论】:
这无法解决此问题,因为用户可以将非数字字符粘贴到文本字段中。 然后你可以使用号码扩展【参考方案13】:虽然这些解决方案中的大多数都可以使用,但请注意,在某些本地化版本中,小数用“,”而不是“。”分隔。
更简洁的方法是
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
let decimalCharacter = NSNumberFormatter().decimalSeparator
let characterSet = NSMutableCharacterSet.decimalDigitCharacterSet()
characterSet.addCharactersInString(decimalCharacter)
return replacementString.rangeOfCharacterFromSet(characterSet.invertedSet) == nil
【讨论】:
【参考方案14】:在 swift 3.0 中测试
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
let numberOnly = NSCharacterSet.init(charactersIn: "0123456789")
let stringFromTextField = NSCharacterSet.init(charactersIn: string)
let strValid = numberOnly.isSuperset(of: stringFromTextField as CharacterSet)
return strValid
【讨论】:
【参考方案15】:这是一个更清洁的解决方案:
guard CharacterSet(charactersIn: "123456789").isSuperset(of: CharacterSet(charactersIn: string)) else
return false
return true
对于小数只需添加.
,例如123456789.
【讨论】:
这有点好,但与这个使用 UITextfiled 委托相比。【参考方案16】:设置 KeyboardType 属性:- 数字键盘 TextField Delegate 请写下代码
func textField(_ textField: UITextField, shouldChangeCharactersIn
range: NSRange, replacementString string: String) -> Bool
if textField.text?.count == 0 && string == "0"
return false
return string == string.filter("0123456789".contains)
数字不能从0开始,输入数字+ve。
【讨论】:
【参考方案17】:我在阅读 Big Nerd Ranch 书时实际上已经这样做了,我的解决方案是:
func textField(textField: UITextField,
shouldChangeCharactersInRange range: NSRange,
replacementString string: String) -> Bool
let newCharacters = NSCharacterSet(charactersInString: string)
return NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(newCharacters)
这只允许数字0-9,允许“。”也更复杂,因为您只能允许一个“。”
【讨论】:
【参考方案18】:func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
if let numRange = string.rangeOfCharacterFromSet(NSCharacterSet.letterCharacterSet())
return false
else
return true
【讨论】:
【参考方案19】:要只允许数字和一个小数运算符,您可以使用以下解决方案:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
let isNumber = NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(NSCharacterSet(charactersInString: string))
return isNumber || (string == NSNumberFormatter().decimalSeparator && textField.text?.containsString(string) == false)
【讨论】:
【参考方案20】:func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
let textString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
if textField == self.phoneTextField && string.characters.count > 0
let numberOnly = NSCharacterSet.decimalDigits
let strValid = numberOnly.contains(UnicodeScalar.init(string)!)
return strValid && textString.characters.count <= 10
return true
上面的代码在 swift 3 中工作 NSCharacterSet.decimalDigits 您也只能使用字母 NSCharacterSet.字母 和大写、小写和、字母数字、空格 使用相同的代码 或See the Link
【讨论】:
【参考方案21】:我认为你可以通过实现 UITextInputTraits 协议,可选的 var keyboardType 来强制改变键盘类型
//class ViewController: UIViewController, UITextInputTraits
@IBOutlet weak var textFieldKeyboardType: UITextField!
didSet
textFieldKeyboardType.keyboardType = UIKeyboardType.NumberPad
var keyboardType: UIKeyboardType
get
return textFieldKeyboardType.keyboardType
set
if newValue != UIKeyboardType.NumberPad
self.keyboardType = UIKeyboardType.NumberPad
【讨论】:
【参考方案22】:这是一个可读性更强的版本,将“0-9”加上“.”:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
let existingTextHasDecimal = textField.text?.rangeOfString(".")
let replacementTextHasDecimal = string.rangeOfString(".")
let replacementTextAllCharacters = NSCharacterSet(charactersInString: string)
let replacementTextOnlyDigits = NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(replacementTextAllCharacters)
if replacementTextHasDecimal != nil && existingTextHasDecimal != nil
return false
else
if replacementTextOnlyDigits == true
return true
else if replacementTextHasDecimal != nil
return true
else
return false
【讨论】:
【参考方案23】:好像没有足够的答案,这是我的。我认为允许使用小数分隔符的每个示例在本地化、退格或复制/粘贴方面都有缺陷。
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
if string.isEmpty return true //allow for backspace
let decimalSeparator = NSNumberFormatter().decimalSeparator ?? "."
let validChars = NSMutableCharacterSet(charactersInString: decimalSeparator)
validChars.formUnionWithCharacterSet(NSCharacterSet.decimalDigitCharacterSet())
if validChars.isSupersetOfSet(NSCharacterSet(charactersInString: string))
switch string.componentsSeparatedByString(decimalSeparator).count-1
case 0: //no decimals
return true
case 1: //if adding decimal, only allow if no existing decimal
if let existingText = textField.text
return existingText.componentsSeparatedByString(decimalSeparator).count <= 1
else return true
default: //invalid decimals
return false
return false
【讨论】:
【参考方案24】:以下是我在 Swift 3.0 中使用的代码,改编自 H 先生的代码。差异是因为:
a) Swift 3.0 中的委托函数声明已更改。 New declaration here
b) NSCharacterSet 声明已更改。
func textField(_ shouldChangeCharactersIntextField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
let inverseSet = NSCharacterSet(charactersIn:"0123456789").inverted
let components = string.components(separatedBy: inverseSet)
let filtered = components.joined(separator: "")
return string == filtered
【讨论】:
【参考方案25】:我已经编辑了 Raj Joshi 的版本以允许使用一个点或一个逗号:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
let inverseSet = CharacterSet(charactersIn:"0123456789").inverted
let components = string.components(separatedBy: inverseSet)
let filtered = components.joined(separator: "")
if filtered == string
return true
else
if string == "." || string == ","
let countDots = textField.text!.components(separatedBy:".").count - 1
let countCommas = textField.text!.components(separatedBy:",").count - 1
if countDots == 0 && countCommas == 0
return true
else
return false
else
return false
【讨论】:
【参考方案26】:如果您想允许小数分隔符和/或负数,您可以使用此代码。 但此代码允许示例:“34”。 (末尾的小数分隔符)同时更改文本。所以你必须添加一些代码示例:textFieldShouldReturn 或 textFieldShouldEndEditing 委托函数。
用 Swift 4 编写的代码,但我认为这与 Swift 3 兼容。
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
guard let text = textField.text else
return true
let replaced = (text as NSString).replacingCharacters(in: range, with: string)
let decimalSeparator = NSLocale.current.decimalSeparator ?? ""
// When user wants to delete las character
if replaced == "" || replaced == "-" || replaced == "-0"
textField.text = "0"
return false
// When text contains 0 before replace except "0."
if replaced != "0" + decimalSeparator && replaced.hasPrefix("0") && text.underestimatedCount == 1
textField.text = replaced.substring(from: replaced.index(after: replaced.startIndex))
return false
// When user wants to delete minus sign
if text.hasPrefix("-") && text.substring(from: text.index(after: text.startIndex)) == replaced
return false
// When user wants to delete before decimal separator
if replaced.hasPrefix(decimalSeparator) || replaced.hasPrefix("-" + decimalSeparator)
return false
// When user wants to add zero the beginning of number... but allowing "0." or "-0." numbers
let testReplaced = replaced.hasPrefix("-") ? replaced.substring(from: replaced.index(after: replaced.startIndex)) : replaced
if testReplaced.count >= 2 && testReplaced.hasPrefix("0") && !testReplaced.hasPrefix("0" + decimalSeparator)
return false
// Every other cases
let allowDecimal = self.allowFloat ? (decimalSeparator == "." ? "\\.?" : decimalSeparator + "?") : ""
let allowSign = self.allowSigned ? "-?" : ""
let pattern = "\(allowSign)[0-9]+\(allowDecimal)([0-9]+)?"
do
let regexRange = (replaced as NSString).range(of: replaced)
let regex = try NSRegularExpression(pattern: pattern, options: [])
let matches = regex.matches(in: replaced, options: [], range: regexRange)
return matches.count == 1 && matches.first!.range == regexRange
catch
return false
如果你不想允许小数或负数,你必须用下一行替换两个变量
let allowDecimal = ""
let allowSign = ""
【讨论】:
【参考方案27】:允许一些字符
func CheckAddress(string:String) -> Bool
let numberOnly = NSCharacterSet.init(charactersIn: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-@,&#/")
let stringFromTextField = NSCharacterSet.init(charactersIn: string)
return numberOnly.isSuperset(of: stringFromTextField as CharacterSet)
print("\(CheckAddress(string: "123"))") //True
print("\(CheckAddress(string: "asdf-"))") //True
print("\(CheckAddress(string: "asd123$"))") //false
【讨论】:
【参考方案28】:以下解决方案有两个好处:
-
这是一行代码
它限制输入,以便输入字段中的整体文本是有效数字。其他解决方案将数字限制为有效数字,但这会导致用户能够输入“4...5”
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
return NumberFormatter().numberFrom(text: (textField.text ?? "") + string) != nil
【讨论】:
【参考方案29】:Swift 2.0
func textField(textField: UITextField,
shouldChangeCharactersInRange range: NSRange,
replacementString string: String) -> Bool
let inverseSet = NSCharacterSet(charactersInString:"0123456789").invertedSet
let components = string.componentsSeparatedByCharactersInSet(inverseSet)
let filtered = components.joinWithSeparator("")
return string == filtered
【讨论】:
【参考方案30】:func isValidNumber(str:String) -> Bool
if str.isEmpty
return false
let newChar = NSCharacterSet(charactersInString: str)
let boolValid = NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(newChar)
if boolValid
return true
else
let lst = str.componentsSeparatedByString(".")
let newStr = lst.joinWithSeparator("")
let currentChar = NSCharacterSet(charactersInString: newStr)
if lst.count == 2 && !lst.contains("") && NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(currentChar)
return true
return false
如果有的话,把这个函数放在你的“提交”或“保存”方法中。
【讨论】:
以上是关于如何限制 UITextField 在 Swift 中只接受数字?的主要内容,如果未能解决你的问题,请参考以下文章
仅允许 UITextField 输入 Swift iOS8 的电子邮件 [重复]
如何在 swift 2 中将 UITextField 保存到核心数据?