Chỉ cho phép Số cho đầu vào UITextField


82

IPad không có bàn phím "Numpad" như iPhone / iPod.

Tôi đang tìm cách hạn chế bàn phím của người dùng chỉ chấp nhận các giá trị từ 0 đến 9.

Tôi sẽ tưởng tượng bằng cách sử dụng "shouldChangeCharactersInRange" của UITextField nhưng tôi không biết cách tốt nhất để triển khai nó.


Tôi đã thực hiện một hướng dẫn về cách thực hiện điều này với mã nguồn dự án có thể tải xuống. Tại đây: xcodenoobies.blogspot.com/2013/12/…
GeneCode

Câu trả lời:


86

Đây là cách bạn có thể xử lý sự cố trên trường xác minh SSN, bạn có thể sửa đổi độ dài tối đa và xóa ifcâu lệnh kiểm tra loại bàn phím nếu cần.

Ngoài ra còn có logic để loại bỏ các cảnh báo độ dài tối đa khi người dùng đang nhập chứ không phải dán dữ liệu.

Trong ngữ cảnh của mã này, presentAlert()/presentAlert:chỉ là một số hàm cơ bản trình bày một UIAlertController(hoặc một kế thừa UIAlertView) bằng cách sử dụng chuỗi thông báo được truyền vào.

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
}

Objective-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
Cảm ơn! Phần 'xóa các ký tự không hợp lệ khỏi đầu vào, nếu bàn phím là bàn phím số' đã giúp trả lời câu hỏi của tôi!
Demasterpl

@Gargo câu hỏi nói rõ rằng các giá trị duy nhất được phép phải là các chữ số từ 0 đến 9. Ký tự dấu chấm không nằm trong các yêu cầu đó. Để cho phép ký tự thời kỳ, người ta có thể xem câu trả lời do Aje đưa ra tại đây .
Beltalowda

đã sử dụng nó nhưng nó để lại vấn đề với các số 0 ở đầu
Gargo

@Gargo, bạn có thể sử dụng thứ gì đó tương tự như những gì anh ta có để phát hiện các ký tự dấu chấm khác và chỉ trả về có cho một ký tự 0 nếu: trường văn bản hiện đang trống, nếu điểm chèn ở chỉ mục 0 và ký tự tiếp theo là dấu chấm, hoặc nếu điểm chèn ở chỉ số lớn hơn chỉ số của ký tự dấu chấm hiện có. Ít nhất đó sẽ là một cách tôi có thể kiểm tra để đảm bảo rằng số 0 được nhập sẽ không tạo ra vấn đề số 0 hàng đầu.
Beltalowda

26

Bạn có thể sử dụng mã này để chỉ cho phép đánh số trong textField.

Trước đại biểu đặt đó cho textField

      textFieldName.delegate=self;

hoặc là

      [textFieldName setDelegate:self];

Hơn sử dụng mã này để chỉ cho phép chữ số vào textField

      - (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, đối với những người khác sử dụng mã này, [string intValue]trả về 0 cho @ "0" - vì vậy if ([string intValue])không được đáp ứng cho @ "0". Tốt hơn để sử dụngif ([string rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location != NSNotFound)
CharlesA

2
@".".intValuelà 0. Và @"0".intValuecũng là 0.
Jaybo

Để làm rõ các nhận xét khác ở đây: Mã này không cho phép người dùng nhập 0ký tự không ( ).
Beltalowda

22

Hãy thử cách này để tránh sự cố xóa trường văn bản

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
Bạn có thể đơn giản hóa phương pháp ủy quyền và chỉ cần tráireturn guard CharacterSet(charactersIn: "0123456789").isSuperset(of: CharacterSet(charactersIn: string))
hamsternik

Tôi đã sao chép và dán vào mã của mình và không hoạt động. Làm cách nào để kết nối nó và làm cho nó hoạt động?
Yash Jain

đầu tiên đặt đại biểu textField (textField.delegate = self) và tuân theo giao thức UITextFieldDelegate đó là nó.
SPatel

19

Các bước rất cụ thể cho mã Swift

Bạn có thể cung cấp logic giới hạn đầu vào của trường văn bản trong func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Boolphương thức bằng cách triển khai UITextFieldDelegategiao thức.

Để rõ ràng, các bước này giả định rằng bảng phân cảnh của bạn chứa Bộ điều khiển dạng xem với đối tượng trường văn bản chỉ chấp nhận các chữ số.

  1. Tạo một lớp tùy chỉnh cho bộ điều khiển chế độ xem mở rộng UIViewController. Đảm bảo rằng cảnh trong bảng phân cảnh của bạn tham chiếu đến lớp tùy chỉnh bằng cách đặt giá trị lớp tùy chỉnh trong Trình kiểm tra danh tính của Xcode.

    import UIKit
    class YourCustomController: UIViewController {
        override func viewDidLoad() {        
            super.viewDidLoad()
        }
    }
    
  2. Tạo một lối thoát từ trường văn bản của cảnh đến Bộ điều khiển Chế độ xem tùy chỉnh của bạn.

    class YourCustomController: UIViewController {
        @IBOutlet weak var numberField: UITextField!
        ...
    }
    
  3. Áp dụng UITextFieldDelegategiao thức trong bộ điều khiển chế độ xem tùy chỉnh của bạn.

    class YourCustomController: UIViewController, UITextFieldDelegate {
        ...
    }
    
  4. Trong viewDidLoadphương thức của bộ điều khiển chế độ xem tùy chỉnh của bạn , chỉ định đại biểu của trường văn bản cho lớp bộ điều khiển chế độ xem tùy chỉnh của bạn.

    override func viewDidLoad() {        
        super.viewDidLoad()
        numberField.delegate = self
    }
    
  5. Thêm UITextFieldDelegate's func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Boolphương pháp.

    Kết quả của việc đặt bộ điều khiển chế độ xem tùy chỉnh của bạn làm numberFieldđại biểu của trong bước trước, phương thức này sẽ được gọi mỗi khi người dùng nhập một ký tự vào trường văn bản. Nếu phương thức của bạn trả về truethì ký tự sẽ vẫn còn trong trường văn bản. Nếu phương thức của bạn trả về falsethì ký tự sẽ không còn trong trường văn bản.

    Các stringtham số là các nhân vật được nhập vào bởi người sử dụng. Nếu stringký tự có thể được chuyển đổi thành một Intthì nó nằm trong khoảng từ 0 đến 9; nếu không, nó là một số ký tự không phải số.

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

(Xem bên dưới để biết mã bộ điều khiển chế độ xem đầy đủ.)


Ví dụ View Controller với trường văn bản chỉ có chữ số

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

Bộ điều khiển Chế độ xem Ví dụ với trường văn bản Thập phân

Nếu bạn muốn hỗ trợ một số thập phân thì hãy tận dụng NSNumberFormatter. Xem các bình luận mã để biết sự khác biệt.

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

2
Điều này là tốt nhưng đã thực hiện một điều chỉnh nhỏ vì nó không cho phép bạn xóa bất kỳ thứ gì trong trường mà không kiểm tra chuỗi trống. Tôi cũng đã thêm khả năng phủ định bằng cách kiểm tra ký tự đầu tiên if (string == "-" && range.location == 0) || chuỗi == "" {return true} trở string.toInt () = nil!
ickydime

return string.toInt() != nil Làm việc như người ở. Cảm ơn!
CalZone

Lưu ý trong Swift 2, tôi đã phải thay đổi điều này thànhreturn Int(string) != nil
nevster

@nevster Cảm ơn đã nhận xét! Tôi nghĩ rằng hầu hết các nhà phát triển Swift đã chuyển hoặc sẽ chuyển sang Swift 2 trở lên. Do đó, tôi đã cập nhật câu trả lời để phù hợp với chuyển đổi chuỗi thành int của Swift 2.
whyceewhite

7
Một thay đổi nữa mà tôi phải thực hiện - phím xóa không còn hoạt động! Vì vậy, tôi đã thay đổi nó thànhreturn 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
Điều này hoạt động tốt cho phân số juste, bạn cần thay đổi newString bên phải: NSString * newString = [textField.text stringByReplacingCharactersInRange: range withString: string];
Idali

7

Tôi đã áp dụng điều này và nó hoạt động !!

-(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
Để thêm ".", Hãy thay thế if (character < 48) return NO; // 48 unichar for 0 if (character > 57) return NO; // 57 unichar for 9bằng, if ((character < 48 || character > 57) && character != 46)tôi cũng khuyên bạn nên so sánh charactervới biểu thị số thập lục phân vì số thập lục phân thường được sử dụng nhất trong những trường hợp này. Tức là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

Trong Swift:

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

1

nhanh chóng 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)
}

Bây giờ bạn chỉ có thể nhấn vào 1234567890 mà thôi


làm thế nào để bạn thực hiện điều này? chỉ tạo chức năng này sẽ không kết nối nó với UITextfield
Yash Jain

0

Giữ dữ liệu trình bày khác biệt với đại diện nội bộ. Có một cách đơn giản hơn. Hãy NSNumberFormatterthực hiện công việc:

 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

Nếu bạn sử dụng mẫu đặc tả của tôi thì mã sẽ như thế này

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
}

Làm cách nào để hạn chế trường UIText chỉ nhận số và giới hạn số lượng từ 6 đến 8?
Marco Almeida

Hi @MarcoAlmeida hãy nhìn vào SwiftyFORM khuôn khổ của tôi, nó có thể sống text Validate, github.com/neoneye/SwiftyFORM
neoneye

0

Tôi đã sửa đổi câu trả lời của @ iDev để phù hợp với chữ số và ".":

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

nhanh chóng 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

Sử dụng mã này:

NSString* val = [[textField text] stringByReplacingCharactersInRange:range withString:string];
NSCharacterSet *allowedCharacterSet = [NSCharacterSet decimalDigitCharacterSet];
if ([[string componentsSeparatedByCharactersInSet:[allowedCharacterSet invertedSet]] count] > 1 || [val length] > 5) {
    return NO;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.