Zezwalaj tylko na liczby dla danych wejściowych UITextField


82

IPad nie ma klawiatury numerycznej, tak jak ma to miejsce w przypadku iPhone'a / iPoda.

Szukam sposobu, aby ograniczyć klawiaturę użytkownika do akceptowania tylko wartości od 0 do 9.

Wyobrażałbym sobie użycie „shouldChangeCharactersInRange” UITextField, ale nie znam najlepszego sposobu na jego implementację.


Stworzyłem poradnik, jak to osiągnąć za pomocą kodu źródłowego projektu do pobrania. Tutaj: xcodenoobies.blogspot.com/2013/12/ ...
GeneCode

Odpowiedzi:


86

W ten sposób możesz poradzić sobie z problemem w polu weryfikacji numeru SSN, możesz zmodyfikować maksymalną długość i usunąć ifinstrukcję sprawdzania typu klawiatury, jeśli zajdzie taka potrzeba.

Istnieje również logika, która blokuje alerty o maksymalnej długości, gdy użytkownik pisze, w przeciwieństwie do wklejania danych.

W kontekście tego kodu presentAlert()/presentAlert:jest tylko kilka podstawowych funkcji, które przedstawiają plik UIAlertController(lub starszyUIAlertView ) przy użyciu przekazanego ciągu komunikatu.

Szybki 5

// NOTE: This code assumes you have set the UITextField(s)'s delegate property to the 
// object that will contain this code, because otherwise it would never be called.
//
// There are also some better stylistic approaches in Swift to avoid all the 
// nested statements, but I wanted to keep the styles similar to allow others 
// to contrast and compare between the two languages a little easier.

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

    // Handle backspace/delete
    guard !string.isEmpty else {

        // Backspace detected, allow text change, no need to process the text any further
        return true
    }

    // Input Validation
    // Prevent invalid character input, if keyboard is numberpad
    if textField.keyboardType == .numberPad {

        // Check for invalid input characters
        if CharacterSet(charactersIn: "0123456789").isSuperset(of: CharacterSet(charactersIn: string)) {

            // Present alert so the user knows what went wrong
            presentAlert("This field accepts only numeric entries.")

            // Invalid characters detected, disallow text change
            return false
        }
    }

    // Length Processing
    // Need to convert the NSRange to a Swift-appropriate type
    if let text = textField.text, let range = Range(range, in: text) {

        let proposedText = text.replacingCharacters(in: range, with: string)

        // Check proposed text length does not exceed max character count
        guard proposedText.count <= maxCharacters else {

            // Present alert if pasting text
            // easy: pasted data has a length greater than 1; who copy/pastes one character?
            if string.count > 1 {

                // Pasting text, present alert so the user knows what went wrong
                presentAlert("Paste failed: Maximum character count exceeded.")
            }

            // Character count exceeded, disallow text change
            return false
        }

        // Only enable the OK/submit button if they have entered all numbers for the last four
        // of their SSN (prevents early submissions/trips to authentication server, etc)
        answerButton.isEnabled = (proposedText.count == 4)
    }

    // Allow text change
    return true
}

Cel C

// NOTE: This code assumes you have set the UITextField(s)'s delegate property to the 
// object that will contain this code, because otherwise it would never be called.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    // Handle backspace/delete
    if (!string.length)
    {
        // Backspace detected, allow text change, no need to process the text any further
        return YES;
    }

    // Input Validation
    // Prevent invalid character input, if keyboard is numberpad
    if (textField.keyboardType == UIKeyboardTypeNumberPad)
    {
        if ([string rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet].invertedSet].location != NSNotFound)
        {
            [self presentAlert: @"This field accepts only numeric entries."];
            return NO;
        }
    }

    // Length Validation
    NSString *proposedText = [textField.text stringByReplacingCharactersInRange:range withString:string];

    // Check proposed text length does not exceed max character count
    if (proposedText.length > maxCharacters)
    {
        // Present alert if pasting text
        // easy: pasted data has a length greater than 1; who copy/pastes one character?
        if (string.length > 1)
        {
            // Pasting text, present alert so the user knows what went wrong
            [self presentAlert: @"Paste failed: Maximum character count exceeded."];
        }

        // Character count exceeded, disallow text change
        return NO;
    }

    // Only enable the OK/submit button if they have entered all numbers for the last four
    // of their SSN (prevents early submissions/trips to authentication server, etc)
    self.answerButton.enabled = (proposedText.length == maxCharacters);

    // Allow text change
    return YES;
}

2
Dzięki! Sekcja „usuń nieprawidłowe znaki z danych wejściowych, jeśli klawiatura jest klawiaturą numeryczną” pomogła odpowiedzieć na moje pytanie!
Demasterpl

@Gargo pytanie wyraźnie mówi, że jedynymi dozwolonymi wartościami powinny być cyfry od 0 do 9. Znak kropki nie spełnia tych wymagań. Aby pozwolić na znak kropki, można zobaczyć odpowiedź udzieloną przez Aje tutaj .
Beltalowda

już go użyłem, ale pozostawia problem z zerami na początku
Gargo

@Gargo możesz użyć czegoś podobnego do tego, co ma do wykrywania innych znaków kropki i zwracać tak tylko dla znaku zerowego, jeśli: pole tekstowe jest obecnie puste, jeśli punkt wstawiania znajduje się pod indeksem 0, a następny znak to kropka lub jeśli punkt wstawiania ma indeks większy niż istniejący znak kropki. Przynajmniej byłby to jeden ze sposobów, w jaki mógłbym sprawdzić, czy wprowadzenie zera nie spowoduje problemu z zerem wiodącym.
Beltalowda

26

Możesz użyć tego kodu, aby zezwolić tylko na liczbę w textField.

Wcześniej ustaw delegata dla textField

      textFieldName.delegate=self;

lub

      [textFieldName setDelegate:self];

Następnie użyj tego kodu, aby dopuścić tylko cyfry do pola tekstowego

      - (BOOL) textField: (UITextField *)theTextField shouldChangeCharactersInRange:(NSRange)range replacementString: (NSString *)string {
//return yes or no after comparing the characters

      // allow backspace
      if (!string.length)
      {
           return YES;
      }

      ////for Decimal value start//////This code use use for allowing single decimal value
      //    if ([theTextField.text rangeOfString:@"."].location == NSNotFound)
      //    {
      //        if ([string isEqualToString:@"."]) {
      //            return YES;
      //        }
      //    }
      //    else
      //    {
      //        if ([[theTextField.text substringFromIndex:[theTextField.text rangeOfString:@"."].location] length]>2)   // this allow 2 digit after decimal 
      //        {
      //            return NO;
      //        }
      //    }
      ////for Decimal value End//////This code use use for allowing single decimal value

      // allow digit 0 to 9
      if ([string intValue])
      {
            return YES;
      }

      return NO;
    }

5
btw, dla innych używających tego kodu, [string intValue]zwraca 0 dla @ „0” - więc if ([string intValue])nie jest spełnione dla @ „0”. Lepszy w użyciuif ([string rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location != NSNotFound)
CharlesA

2
@".".intValuewynosi 0. I też @"0".intValuewynosi 0.
Jaybo,

Aby wyjaśnić inne komentarze tutaj: Ten kod nie pozwala użytkownikowi na wpisanie 0znaku zero ( ).
Beltalowda

23

Spróbuj tego, aby uniknąć problemu z czyszczeniem pól tekstowych

Swift 3.0

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    guard NSCharacterSet(charactersInString: "0123456789").isSupersetOfSet(NSCharacterSet(charactersInString: string)) else {
        return false
    }
    return true
}

Swift 4.0

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard CharacterSet(charactersIn: "0123456789").isSuperset(of: CharacterSet(charactersIn: string)) else {
        return false
    }
    return true
}

2
Możesz uprościć metodę delegowania i po prostu wyszedłreturn guard CharacterSet(charactersIn: "0123456789").isSuperset(of: CharacterSet(charactersIn: string))
hamsternik

Skopiowałem i wkleiłem do mojego kodu i nie działa. Jak to podłączyć i sprawić, by działało?
Yash Jain

Najpierw ustaw delegata textField (textField.delegate = self) i dostosuj protokół UITextFieldDelegate to wszystko.
SPatel,

19

Bardzo specyficzne kroki dla kodu Swift

Możesz zapewnić logikę ograniczającą dane wejściowe pola tekstowego w func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Boolmetodzie, implementując UITextFieldDelegateprotokół.

Dla jasności w tych krokach założono, że scenorys zawiera kontroler widoku z obiektem pola tekstowego, który powinien akceptować tylko cyfry.

  1. Utwórz klasę niestandardową dla kontrolera widoku, który rozszerza UIViewController. Upewnij się, że scena w serii ujęć odnosi się do klasy niestandardowej, ustawiając wartość klasy niestandardowej w Inspektorze tożsamości Xcode.

    import UIKit
    class YourCustomController: UIViewController {
        override func viewDidLoad() {        
            super.viewDidLoad()
        }
    }
    
  2. Utwórz wylot z pola tekstowego sceny do własnego kontrolera widoku.

    class YourCustomController: UIViewController {
        @IBOutlet weak var numberField: UITextField!
        ...
    }
    
  3. Zastosuj UITextFieldDelegateprotokół w niestandardowym kontrolerze widoku.

    class YourCustomController: UIViewController, UITextFieldDelegate {
        ...
    }
    
  4. W viewDidLoadmetodzie kontrolera widoku niestandardowego przypisz delegata pola tekstowego do klasy kontrolera widoku niestandardowego.

    override func viewDidLoad() {        
        super.viewDidLoad()
        numberField.delegate = self
    }
    
  5. Dodaj UITextFieldDelegate„s func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Boolmetody.

    W wyniku ustawienia numberFielddelegata niestandardowego kontrolera widoku jako delegata w poprzednim kroku, ta metoda będzie wywoływana za każdym razem, gdy użytkownik wprowadzi znak do pola tekstowego. Jeśli metoda powróci, trueznak pozostanie w polu tekstowym. Jeśli metoda powróci, falseznak nie pozostanie w polu tekstowym.

    stringParametrem jest znak wprowadzanego przez użytkownika. Jeśli stringznak można zamienić na an, Intto jest między 0 a 9; w przeciwnym razie jest to jakiś znak niebędący liczbą.

    class YourCustomController: UIViewController, UITextFieldDelegate {
        ...
        func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    
            return Int(string) != nil
        }
    }
    

(Zobacz poniżej pełny kod kontrolera).


Przykład kontrolera widoku z polem tekstowym zawierającym tylko cyfry

import UIKit

class YourCustomController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var numberField: UITextField!

    override func viewDidLoad() {        
        super.viewDidLoad()       
        numberField.delegate = self
    }

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {        
        return Int(string) != nil
    }    
}

Przykładowy kontroler widoku z dziesiętnym polem tekstowym

Jeśli chcesz obsługiwać liczbę dziesiętną, skorzystaj z NSNumberFormatter. Zobacz komentarze do kodu dotyczące różnic.

import UIKit

class YourCustomController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var numberField: UITextField!

    private var formatter: NSNumberFormatter!

    override func viewDidLoad() {        
        super.viewDidLoad()       
        numberField.delegate = self

        // Initialize the formatter; minimum value is set to zero; style is Decimal. 
        formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
        formatter.minimum = 0
    }

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        // Combine the current text field value and the new string
        // character. If it conforms to the formatter's settings then
        // it is valid. If it doesn't then nil is returned and the
        // string character should not be allowed in the text field.         
        return formatter.numberFromString("\(textField.text)\(string)") != nil
    }    
}

3
To jest dobre, ale wprowadzono niewielką korektę, ponieważ nie pozwala na usunięcie niczego w polu bez sprawdzenia pustego ciągu. Dodałem również możliwość ujemnego, sprawdzając pierwszy znak if (string == "-" && range.location == 0) || string == "" {return true} return string.toInt ()! = nil
ickydime

return string.toInt() != nil Działał jak urok. Dzięki!
CalZone

Uwaga w Swift 2 musiałem zmienić to nareturn Int(string) != nil
Nevster

@nevster Dzięki za komentarz! Myślę, że większość programistów Swift przeniosła się lub będzie przenosić się na Swift 2 i nowsze. Dlatego zaktualizowałem odpowiedź, aby była zgodna z konwersją string-to-int w Swift 2.
whyceewhite

7
Jeszcze jedna zmiana, którą musiałem wprowadzić - klawisz usuwania już nie działał! Więc zmieniłem to nareturn string == "" || Int(string) != nil
nevster

9
- (BOOL) textField: (UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString: (NSString *)string {

    NSNumberFormatter * nf = [[NSNumberFormatter alloc] init];
    [nf setNumberStyle:NSNumberFormatterNoStyle];

    NSString * newString = [NSString stringWithFormat:@"%@%@",textField.text,string];
    NSNumber * number = [nf numberFromString:newString];

    if (number)
        return YES;
    else
       return NO;
}

1
Działa to dobrze w przypadku ułamków juste, musisz zmienić właściwy newString: NSString * newString = [textField.text stringByReplacingCharactersInRange: range withString: string];
Idali

7

Zastosowałem to i działa !!

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
// Check for non-numeric characters
NSUInteger lengthOfString = string.length;
for (NSInteger index = 0; index < lengthOfString; index++) {
    unichar character = [string characterAtIndex:index];
    if (character < 48) return NO; // 48 unichar for 0
    if (character > 57) return NO; // 57 unichar for 9
}
// Check total length for restrict user
NSUInteger proposedNewLength = textField.text.length - range.length + string.length;
if (proposedNewLength > 6)
    return YES;
return YES;                                                                                                                                     
}

1
Aby dodać „”, należy wymienić if (character < 48) return NO; // 48 unichar for 0 if (character > 57) return NO; // 57 unichar for 9z if ((character < 48 || character > 57) && character != 46)Chciałbym dodatkowo zalecamy porównać characterdo reprezentacji szesnastkowy liczb hexadecymalnie są najczęściej stosowane w tych okolicznościach. Tj.if ((character < 0x30 || character > 0x39) && character != 0x2E)
Jacob R

2
NSString* val = [[textField text] stringByReplacingCharactersInRange:range withString:string];
    NSCharacterSet *allowedCharacterSet = [NSCharacterSet decimalDigitCharacterSet];
    if ([[string componentsSeparatedByCharactersInSet:[allowedCharacterSet invertedSet]] count] > 1 || [val length] > 5) {
        return NO;
    }

2
Works fine for me :

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (([string rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location != NSNotFound) && !(range.length==1 && string.length==0)) {
            return NO;
        }
        return YES;
    }

1

W Swift:

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        return string.isEmpty || Int(string) != nil
    }

1

szybki 5

    //MARK:- UITextFieldDelegate

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

    let allowedCharacters = "1234567890"
    let allowedCharcterSet = CharacterSet(charactersIn: allowedCharacters)
    let typedCharcterSet = CharacterSet(charactersIn: string)
    return allowedCharcterSet.isSuperset(of: typedCharcterSet)
}

Możesz teraz po prostu dotknąć tylko 1234567890


jak to wdrażasz? samo utworzenie tej funkcji nie połączy jej z UITextfield
Yash Jain

0

Zachowaj odrębne dane prezentacji od wewnętrznej reprezentacji. Jest prostszy sposób. Zróbmy NSNumberFormatterrobotę:

 NSNumberFormatter* ns = [[NSNumberFormatter alloc] init];
 ns.numberStyle = NSNumberFormatterDecimalStyle;
 [ns setMaximumFractionDigits:2];
 // This is your internal representation of the localized number
 double a = [[ns numberFromString:self.textIVA.text] doubleValue]];

[mylabel setText:[NSString stringWithFormat:@"€ %@",
     [NSNumberFormatter localizedStringFromNumber:
                          [NSNumber numberWithDouble:a]
                                      numberStyle:NSNumberFormatterDecimalStyle]]];

0

Jeśli używasz mojego wzorca specyfikacji, kod wygląda następująco

textField.delegate = self

lazy var specification: Specification = {
    return RegularExpressionSpecification(pattern: "^(|0|[1-9]\\d{0,6})$")
}()

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let textFieldString: NSString = textField.text ?? ""
    let s = textFieldString.stringByReplacingCharactersInRange(range, withString:string)
    return specification.isSatisfiedBy(s)
}

func textFieldShouldReturn(textField: UITextField) -> Bool {
    let s = textField.text ?? ""
    let isTextValid = specification.isSatisfiedBy(s)
    if isTextValid {
        textField.resignFirstResponder()
    }
    return false
}

Jak ograniczyć pole UIText, aby odbierać tylko liczby i ograniczyć liczbę liczb od 6 do 8?
Marco Almeida

Cześć @MarcoAlmeida, spójrz na mój framework SwiftyFORM, może on weryfikować tekst na żywo, github.com/neoneye/SwiftyFORM
neoneye

0

Zmodyfikowałem odpowiedź @ iDev na pracę z cyfrowymi i „.”:

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
     // Check for non-numeric characters
     NSUInteger lengthOfString = string.length;
     for (NSInteger index = 0; index < lengthOfString; index++) {
         unichar character = [string characterAtIndex:index];
         if ((character < 48) && (character != 46)) return NO; 
         // 48 unichar for 0, and 46 unichar for point
         if (character > 57) return NO; 
         // 57 unichar for 9
     }
     // Check for total length
     NSUInteger proposedNewLength = textField.text.length - range.length + string.length;
     if (proposedNewLength > 6)
         return YES;
     return YES; 
 }

0

szybki 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
    }

-1

Użyj tego kodu:

NSString* val = [[textField text] stringByReplacingCharactersInRange:range withString:string];
NSCharacterSet *allowedCharacterSet = [NSCharacterSet decimalDigitCharacterSet];
if ([[string componentsSeparatedByCharactersInSet:[allowedCharacterSet invertedSet]] count] > 1 || [val length] > 5) {
    return NO;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.