it-swarm.com.ru

Как ограничить UITextField принимать только цифры в Swift?

Я хочу, чтобы пользователь вводил только числовые значения в UITextField. На iPhone мы можем показать цифровую клавиатуру, но на iPad пользователь может переключиться на любую клавиатуру.

Есть ли способ ограничить пользователя вводить только числовые значения в UITextField?

56
user5034941

Вот мои 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
}
72
Mr H

Решение для 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)
  }
59
Hiren Panchal

Swift 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
        }
    }
}
11
Cian

В 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
}
11
iOS

Принимайте десятичные значения в текстовых полях с одной (.) Точкой в ​​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
        }
    }
}
8
Raj Joshi
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 в соответствующем текстовом поле.

6
ndmeiri

IPhone только решение

В любом UITextField, из которого вы получаете эти значения, вы можете указать тип клавиатуры, которую вы хотите видеть, когда кто-то касается текстового поля.

НАПРИМЕР. только цифровая клавиатура.

Понравился этот скриншот:

 enter image description here

Ipad

IPad не поддерживает цифровую клавиатуру, поэтому вы можете либо не поддерживать iPad, либо проверить поле после отправки, либо следовать одному из других предложений, чтобы создать нормальное поведение при работе на iPad.

6
Jamil Hasnine Tamim

Вот простое решение, вам нужно подключить событие «Редактирование изменено» к этому методу в вашем контроллере.

Swift 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()
        }
    }
}
3
shbli

Использовать числовой форматер

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
 }
3
SPatel

Хотя большинство из этих решений будет работать, имейте в виду, что в некоторых локализациях десятичные дроби разделяются знаком «,», а не «».

Более чистый способ сделать это

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
}
2
AlexLittlejohn

Протестировано в 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
 }
2
iosLearner

Во-первых, вы должны унаследовать класс UITextFieldDelegate с вашим собственным учебный класс

class ViewController: UIViewController, UITextFieldDelegate {

2-й добавить IBOutlet

@IBOutlet weak var firstName: UITextField!

3-й, вы должны убедиться, что этот объект использует

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


      }
  }
2
akbar khan

Я на самом деле сделал это, работая над книгой «Ранчо Большого ботаника», мое решение:

func textField(textField: UITextField, 
    shouldChangeCharactersInRange range: NSRange, 
    replacementString string: String) -> Bool {

    let newCharacters = NSCharacterSet(charactersInString: string)
    return NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(newCharacters)
}

это позволяет только цифры 0-9, чтобы разрешить "." также сложнее, так как вы можете разрешить только один "."

2
sgib
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if let numRange = string.rangeOfCharacterFromSet(NSCharacterSet.letterCharacterSet()) {
        return false
    } else {
        return true
    }
   }
2
likarson

Расширьте свой контроллер вида следующим образом:

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
}

Теперь вы убедитесь, что пользователь может вводить только десятичные цифры.

Swift 4 + Принимает только номер И принимает один разделитель

2
Aftab Ahmed

Чтобы разрешить только цифры и только один десятичный оператор, вы можете использовать это решение:

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)
}
2
hprione

Для некоторых персонажей

func CheckAddress(string:String) -> Bool  {
        let numberOnly = NSCharacterSet.init(charactersIn: "[email protected],&#/")
        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
1
Ilesh
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 .Letters
и верхний регистр, нижний регистр и буквенно-цифровые символы, пробелы используется тот же код или Смотрите ссылку

1
Ramprasath Selvam

Я отредактировал версию Радж Джоши, чтобы разрешить одну точку или одну запятую:

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
        }
    }
}
1
Matthijs

Как будто не хватает ответов, вот мой. Я думаю, что каждый пример, разрешенный для десятичных разделителей, имеет недостатки в локализации, возвратах или копировании/вставке.

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
}
1
David

Ниже приведен код, который я использовал в Swift 3.0, адаптированный из кода мистера Х. Различия заключаются в том, что:

а) Объявление функции делегата было изменено в Swift 3.0. Новая декларация здесь

б) Объявление 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

}
1
ChinLoong

Я думаю, что вы можете принудительно изменить тип клавиатуры, реализуя протокол UITextInputTraits, необязательный var клавиатураType

//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
        }
    } 
}
1
Lukas

Мертвое простое решение для чисел Double (имейте в виду, что это не лучшее удобное для пользователя решение) в вашем делегате UITextFieldDelegate:

func textField(_ textField: UITextField,
               shouldChangeCharactersIn range: NSRange,
               replacementString string: String) -> Bool {
        guard let currentString = textField.text as NSString? else {
            return false
        }
        let newString = currentString.replacingCharacters(in: range, with: string)
        return Double(newString) != nil
}
0
Tomasz Wójcik
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

  }
0
tymac

Это более читаемая версия, которая будет делать «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
        }
    }
}
0
Enraged
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
    }
}

Поместите эту функцию в ваш метод «Отправить» или «Сохранить», если он есть.

0
den330

Свифт 3 

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    if textField==yourTextFieldOutlet {
                if(CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: yourTextFieldOutlet.text!))){
//if numbers only, then your code here
                }
                else{
                showAlert(title: "Error",message: "Enter Number only",type: "failure")
                }
            }
    return true
    }
0
ArgaPK

Вы можете использовать этот код, если хотите разрешить десятичный разделитель и/или отрицательные числа . Но этот код допускает пример: «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 = ""
0
Ferenc Kiss

Вы можете использовать shouldChangeCharactersInRange вместе с методом расширения String, чтобы проверить, является ли входная строка числом или нет. 

extension String  {

    var isNumber : Bool {
        get{
            return !self.isEmpty && self.stringWithoutWhitespaces.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) == nil
        }
    }

    var stringWithoutWhitespaces: String {
        return self.replacingOccurrences(of: " ", with: "")
    }

}

//Mark: shouldChangeCharactersInRange
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    // return true if the string only contains numeric characters
    let isValid = string.stringWithoutWhitespaces.isNumber 
    return valid
}
0
Suhit Patil

Вот более чистое решение: 

 guard CharacterSet(charactersIn: "123456789").isSuperset(of: CharacterSet(charactersIn: string)) else {
     return false
 }
 return true

Для десятичных дробей просто добавьте ., например 123456789.

0
Farhad