UITextField girişi için yalnızca Numbers'a izin ver


82

İPad, iPhone / iPod gibi bir "Numpad" klavyeye sahip değildir.

Kullanıcının klavyesini yalnızca 0 ile 9 arasındaki değerleri kabul edecek şekilde nasıl kısıtlayabileceğimi bulmaya çalışıyorum.

UITextField'ın "shouldChangeCharactersInRange" kullanıldığını düşünürdüm ama bunu uygulamanın en iyi yolunu bilmiyorum.


İndirilebilir proje kaynak kodu ile bunu nasıl başaracağıma dair bir eğitim hazırladım. Burada: xcodenoobies.blogspot.com/2013/12/…
GeneCode

Yanıtlar:


86

Bir SSN doğrulama alanındaki sorunu bu şekilde halledebilirsiniz, maksimum uzunluğu değiştirebilir ve ifgerekirse klavye türü için kontrol ifadesini kaldırabilirsiniz .

Ayrıca, verileri yapıştırmak yerine kullanıcı yazarken maksimum uzunluk uyarılarını bastırma mantığı da vardır.

Bu kod bağlamında, iletilen mesaj dizesini kullanarak presentAlert()/presentAlert:bir UIAlertController(veya eski UIAlertView) sunan bazı temel işlevler vardır .

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

Amaç-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
Teşekkürler! 'Klavye sayısal tuş takımı ise geçersiz karakterleri girişten kaldır' bölümü sorumu yanıtlamaya yardımcı oldu!
Demasterpl

@Gargo soru özellikle, izin verilen tek değerlerin 0 ile 9 arasındaki rakamlar olması gerektiğini belirtir. Nokta karakteri bu gereksinimler dahilinde değildir. Nokta karakterine izin vermek için, Aje tarafından verilen cevabı burada görebilirsiniz .
Beltalowda

zaten kullandı ama sorunu
baştaki

@Gargo, diğer nokta karakterlerini tespit etmek için sahip olduklarına benzer bir şey kullanabilir ve şu durumlarda yalnızca sıfır karakteri için yes döndürür: metin alanı şu anda boşsa, ekleme noktası 0 dizinindeyse ve sonraki karakter bir nokta ise veya ekleme noktası, mevcut bir nokta karakterinden daha büyük bir dizindeyse. En azından bu, girilen sıfırın önde gelen sıfır sorunu yaratmayacağından emin olmak için kontrol etmemin bir yolu olabilir.
Beltalowda

26

TextField'da yalnızca sayıya izin vermek için bu kodu kullanabilirsiniz.

Bundan önce textField için temsilci ayarlayın

      textFieldName.delegate=self;

veya

      [textFieldName setDelegate:self];

Daha sonra bu kodu yalnızca rakamların textField'a dönüştürülmesine izin vermek için kullanın

      - (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, bu kodu kullanan diğerleri [string intValue]için, @ "0" için 0 döndürür - bu nedenle if ([string intValue])@ "0" için karşılanmaz. if ([string rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location != NSNotFound)
Kullanması

2
@".".intValue0. Ve @"0".intValuede 0.
Jaybo

Buradaki diğer yorumları netleştirmek için: Bu kod, kullanıcının sıfır ( 0) karakteri yazmasına izin vermez .
Beltalowda

23

Metin alanı temizleme sorununu önlemek için bunu deneyin

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
Temsilci yöntemini basitleştirebilir ve hemen return guard CharacterSet(charactersIn: "0123456789").isSuperset(of: CharacterSet(charactersIn: string))
çıkabilirsiniz

Kodumu kopyalayıp yapıştırdım ve çalışmıyor. Nasıl bağlarım ve çalışmasını sağlarım?
Yash Jain

ilk olarak textField temsilcisini (textField.delegate = self) ayarlayın ve UITextFieldDelegate protokolüne uyun işte bu.
SPatel

19

Swift kodu için çok özel adımlar

Protokolü func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Booluygulayarak, metin alanının yöntemdeki girişini kısıtlayan mantık sağlayabilirsiniz UITextFieldDelegate.

Netlik açısından, bu adımlar, film şeridinizin yalnızca rakamları kabul etmesi gereken bir metin alanı nesnesine sahip bir Görünüm Denetleyicisi içerdiğini varsayar .

  1. Genişleyen görünüm denetleyicisi için özel bir sınıf oluşturun UIViewController. Xcode'un Kimlik Denetçisi'nde özel sınıf değerini ayarlayarak film şeridinizdeki sahnenin özel sınıfa başvurduğundan emin olun .

    import UIKit
    class YourCustomController: UIViewController {
        override func viewDidLoad() {        
            super.viewDidLoad()
        }
    }
    
  2. Sahnenizin metin alanından özel Görüntü Kontrolörünüze bir çıkış oluşturun.

    class YourCustomController: UIViewController {
        @IBOutlet weak var numberField: UITextField!
        ...
    }
    
  3. Uygula UITextFieldDelegateÖzel görünüm denetleyicisi protokolü.

    class YourCustomController: UIViewController, UITextFieldDelegate {
        ...
    }
    
  4. Özel görünüm denetleyicinizin viewDidLoadyönteminde, metin alanınızın temsilcisini özel görünüm denetleyicisi sınıfınıza atayın.

    override func viewDidLoad() {        
        super.viewDidLoad()
        numberField.delegate = self
    }
    
  5. Ekle UITextFieldDelegatebireyin func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Boolyöntemi.

    Özel görünüm denetleyicinizi numberFieldönceki adımdaki temsilcisi yapmanın bir sonucu olarak , bu yöntem bir kullanıcı metin alanına her karakter girdiğinde çağrılacaktır. Yönteminiz geri dönerse true, karakter metin alanında kalacaktır. Senin yöntem dönerse falseo zaman karakter olacak değil metin alanına kalır.

    stringParametre kullanıcı tarafından girilen olmak karakterdir. Eğer stringkarakteri dönüştürülebilir Intsonra 0 ila 9 arasında olduğu; aksi takdirde, sayı olmayan bir karakterdir.

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

(Tam görünüm denetleyici kodu için aşağıya bakın.)


Yalnızca rakam metin alanına sahip Örnek Görünüm Denetleyici

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

Ondalık metin alanına sahip Örnek Görünüm Denetleyici

Ondalık bir sayıyı desteklemek istiyorsanız, bundan yararlanın NSNumberFormatter. Farklılıklar için kod açıklamalarına bakın.

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
Bu iyidir, ancak alandaki herhangi bir şeyi boş dizge kontrolü yapmadan silmenize izin vermediği için küçük bir ayarlama yapılmıştır. Ayrıca ilk karakteri kontrol ederek negatif yeteneği ekledim if (string == "-" && range.location == 0) || string == "" {return true} return string.toInt ()! = nil
ickydime

return string.toInt() != nil Büyüleyici gibi çalıştı. Teşekkürler!
CalZone

Swift 2'de Not: Bunu şu şekilde değiştirmek zorunda kaldımreturn Int(string) != nil
asla

@nevster Yorum için teşekkürler! Bence çoğu Swift geliştiricisi Swift 2 ve üstüne taşındı veya geçecek. Bu nedenle, cevabı Swift 2'nin dizeden int dönüşümüne uyacak şekilde güncelledim.
whyceewhite

7
Yapmam gereken bir değişiklik daha - silme tuşu artık çalışmıyor! Ben de bunu şu şekilde değiştirdimreturn 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
Bu, kesir için gayet iyi çalışıyor, doğru newString'i değiştirmeniz gerekiyor: NSString * newString = [textField.text stringByReplacingCharactersInRange: range withString: string];
Idali

7

Bunu uyguladım ve işe yarıyor !!

-(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
"." Eklemek için, I if (character < 48) return NO; // 48 unichar for 0 if (character > 57) return NO; // 57 unichar for 9ile değiştirin , if ((character < 48 || character > 57) && character != 46)ek characterolarak, bu durumlarda en yaygın olarak onaltılık sayılar kullanıldığından, sayıların onaltılık gösterimlerini karşılaştırmanızı tavsiye ederim . Yaniif ((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

Swift'de:

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

1

hızlı 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)
}

Artık sadece 1234567890'a dokunabilirsiniz


bunu nasıl uyguluyorsunuz? sadece bu işlevi oluşturmak onu UITextfield'a bağlamaz
Yash Jain

0

Dahili sunumdan farklı sunum verilerini saklayın. Daha basit bir yol var. NSNumberFormatterİşi yapalım :

 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

Spesifikasyon modelimi kullanırsanız, kod şuna benzer

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
}

UIText alanını yalnızca sayı alacak şekilde ve sayıların miktarını 6 ile 8 arasında sınırlayacak şekilde nasıl sınırlayabilirim?
Marco Almeida

Merhaba @MarcoAleleine, SwiftyFORM çerçeveme bir göz atın, geçerliliğini doğrulayan metin, github.com/neoneye/SwiftyFORM
neoneye

0

@ İDev'in cevabını dijitaller ve "." İçin çalışmak üzere değiştirdim:

-(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

hızlı 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

Bu kodu kullanın:

NSString* val = [[textField text] stringByReplacingCharactersInRange:range withString:string];
NSCharacterSet *allowedCharacterSet = [NSCharacterSet decimalDigitCharacterSet];
if ([[string componentsSeparatedByCharactersInSet:[allowedCharacterSet invertedSet]] count] > 1 || [val length] > 5) {
    return NO;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.