Đặt độ dài ký tự tối đa của UITextField trong Swift


85

Tôi biết có những chủ đề khác về vấn đề này nhưng dường như tôi không thể tìm ra cách thực hiện nó.

Tôi đang cố gắng giới hạn một UITextField chỉ có 5 ký tự

Tốt hơn là chữ và số và - và. và _

Tôi đã thấy mã này

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange,
                       replacementString string: String) -> Bool
{
    let maxLength = 4
    let currentString: NSString = textField.text
    let newString: NSString =
             currentString.stringByReplacingCharactersInRange(range, withString: string)
    return newString.length <= maxLength
}

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

    let length = count(textField.text.utf16) + count(string.utf16) - range.length
    return length <= 10 
}

Tôi chỉ không biết làm thế nào để thực sự triển khai nó hoặc tôi nên hoán đổi "trường văn bản" nào cho tùy chỉnh có tên UITextField của mình



Nhanh cảnh báo - để rút ngắn một Stringtrong Swift những ngày này bạn có thể cuối cùng chỉ .prefix (n)
Fattie

Câu trả lời:


134
  1. Bộ điều khiển chế độ xem của bạn phải tuân theo UITextFieldDelegate, như bên dưới:

    class MyViewController: UIViewController, UITextFieldDelegate {
    
    }
    
  2. Đặt người đại diện cho trường văn bản của bạn: myTextField.delegate = self

  3. Triển khai phương pháp trong bộ điều khiển chế độ xem của bạn: textField(_:shouldChangeCharactersInRange:replacementString:)

Tất cả cùng nhau:

class MyViewController: UIViewController,UITextFieldDelegate  //set delegate to class 

@IBOutlet var mytextField: UITextField             //  textfield variable 

override func viewDidLoad() {
    super.viewDidLoad()
    mytextField.delegate = self                  //set delegate
}


func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange,
                       replacementString string: String) -> Bool
{
    let maxLength = 4
    let currentString: NSString = textField.text
    let newString: NSString =
             currentString.stringByReplacingCharactersInRange(range, withString: string)
    return newString.length <= maxLength
}

Đối với Swift 4

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let maxLength = 1
    let currentString: NSString = (textField.text ?? "") as NSString
    let newString: NSString =
        currentString.replacingCharacters(in: range, with: string) as NSString
    return newString.length <= maxLength
}

Chỉ cho phép một nhóm ký tự được chỉ định được nhập vào một trường văn bản nhất định

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
  var result = true
  
  if mytextField == numberField {
    if count(string) > 0 {
      let disallowedCharacterSet = NSCharacterSet(charactersInString: "0123456789.-").invertedSet
      let replacementStringIsLegal = string.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
      result = replacementStringIsLegal
    }
  }
 
  return result
}

Cách lập trình trường văn bản iOS chỉ sử dụng dữ liệu nhập số với độ dài tối đa


Cảm ơn bạn rất nhiều vì đã trả lời nhanh chóng! Nếu tôi đặt một trường văn bản này làm trường đại diện, tôi có thể sửa đổi các trường văn bản khác không?
ishkur88

vâng, và bạn sẽ nhận được textfield trong câu hỏi (được chỉnh sửa) là tham số đầu tiên textFieldtrong phương pháp này func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
Aladin

Nhưng tôi sẽ đặt tham số thứ hai ở đâu? Tôi không tham chiếu lại myTextField sau khi tôi đặt nó làm đại biểu.
ishkur88

Giống như nếu tôi muốn tạo một trường văn bản khác 0-9 chỉ cho số điện thoại.
ishkur88

mỗi khi một trường văn bản đang được chỉnh sửa, lệnh gọi lại shouldChangeCharactersInRangeđược gọi, điều này dành cho tất cả các trường văn bản, bạn nhận lệnh gọi lại ở cùng một nơi shouldChangeCharactersInRangevà bên trong phương thức này, bạn có thể biết trường văn bản nào đang được chỉnh sửa nhờ tham số đã truyền, textFieldví dụ, bạn có thể đưa ra tag cho mỗi textfield và kiểm tra bên trong shouldChangeCharactersInRangevà đối với mỗi textfield thực hiện xác nhận các nội dung
Aladin

113

Tháng 12 năm 2017. Swift 4.

Hãy lưu ý rằng phần lớn mã ví dụ mà bạn sẽ thấy trực tuyến liên quan đến vấn đề này rất lỗi thời .

Dán phần sau vào bất kỳ tệp Swift nào trong dự án của bạn. Bạn có thể đặt tên tệp là bất kỳ thứ gì, ví dụ: "Handy.swift"

Điều này cuối cùng đã khắc phục được một trong những vấn đề ngu ngốc nhất trong iOS:

nhập mô tả hình ảnh ở đây

Các trường văn bản của bạn bây giờ có một .maxLength.

Bạn hoàn toàn có thể đặt giá trị đó trong bảng phân cảnh trong quá trình phát triển hoặc đặt giá trị đó trong mã khi ứng dụng đang chạy.

// simply have this in any Swift file, say, Handy.swift

import UIKit
private var __maxLengths = [UITextField: Int]()
extension UITextField {
    @IBInspectable var maxLength: Int {
        get {
            guard let l = __maxLengths[self] else {
               return 150 // (global default-limit. or just, Int.max)
            }
            return l
        }
        set {
            __maxLengths[self] = newValue
            addTarget(self, action: #selector(fix), for: .editingChanged)
        }
    }
    func fix(textField: UITextField) {
        let t = textField.text
        textField.text = t?.prefix(maxLength)
    }
}

Nó đơn giản mà.


Chú thích cuối trang - những ngày này để cắt ngắn một cách Stringnhanh chóng một cách an toàn , bạn chỉ cần.prefix(n)


Một phiên bản một lần thậm chí còn đơn giản hơn ...

Ở trên sửa tất cả các trường văn bản trong dự án của bạn.

Nếu bạn chỉ muốn một trường văn bản cụ thể chỉ được giới hạn ở nói "4", và đó là ...

class PinCodeEntry: UITextField {
    
    override func didMoveToSuperview() {
        
        super.didMoveToSuperview()
        addTarget(self, action: #selector(fixMe), for: .editingChanged)
    }
    
    @objc private func fixMe() { text = text?.prefix(4) }
}

Phù! Thats tất cả để có nó.

(Chỉ BTW, đây là một mẹo rất hữu ích tương tự liên quan đến Chế độ xem UIText , https://stackoverflow.com/a/42333832/294884 )


Đối với lập trình viên OCD (như tôi) ...

Như @LeoDabus nhắc nhở, .prefix trả về một chuỗi con. Nếu bạn cực kỳ quan tâm, điều này

let t = textField.text
textField.text = t?.prefix(maxLength)

sẽ là

if let t: String = textField.text {
    textField.text = String(t.prefix(maxLength))
}

Thưởng thức!


2
Có vẻ hợp pháp! Cảm ơn bạn.
J. Doe

2
có cái gì như thế này cho textView không?
Dory

13
Rằng tất cả những điều này phải được thực hiện để đạt được một cái gì đó quá phổ biến và quá đơn giản đã thổi bay tâm trí tôi. Họ không thể chỉ cung cấp cho chúng tôi một textField.maxLength đơn giản được tích hợp sẵn ... dù sao thì giải pháp của bạn cũng rất tuyệt, cảm ơn!
mylovemhz

2
Giải pháp này rất tiện dụng nhưng bản đồ các trường văn bản ở trên cùng sẽ thực sự tạo ra một chu kỳ lưu giữ.
Angel G. Olloqui

3
CẢNH BÁO KHI SỬ DỤNG GIẢI PHÁP NÀY! Giải pháp này có một số vấn đề. Một trong số đó là nếu người dùng nhập vào đầu textField, bạn sẽ cho phép họ nhập ký tự mới và ký tự cuối cùng sẽ bị xóa, đồng thời, con trỏ sẽ nhảy đến ký tự cuối cùng trong trường. Một vấn đề khác là nếu bạn đặt văn bản theo chương trình, nó sẽ cho phép bạn đặt văn bản lớn hơn giới hạn. Một vấn đề khác xảy ra nếu bạn hoàn tác một thay đổi (CMD + Z với bàn phím ngoài), nó sẽ bị lỗi nếu bạn đã cố gắng thêm một chữ số vượt quá giới hạn trước đó.
juancazalla

26

Swift 4, chỉ cần sử dụng:

public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    return range.location < 10
}

đây sẽ là câu trả lời được chọn. Đơn giản và hoạt động tốt.
user832

9
Nó không hoạt động. Điều gì sẽ xảy ra nếu bạn nhấn vào giữa chuỗi và bạn có thể nhập nhiều hơn X ký tự.
Slavcho

thay vì range.location <10, bạn có thể sử dụng textField.text.length <10. Giải pháp này đơn giản và trang nhã.
Saqib Saud

Bạn có thể sử dụng giải pháp này: if textField.text? .Count> = 12 {return false}
Сергей Билык

1
nó không hoạt động khi quá khứ một văn bản nếu bạn muốn làm việc trong hành động trước đây, bạn nên thêmstring.count < MAX_LENGTH
Reza Dehnavi

12

Tương tự như cách Steven Schmatz đã làm nhưng sử dụng Swift 3.0:

//max Length
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
               replacementString string: String) -> Bool
{
    let maxLength = 4
    let currentString: NSString = textField.text! as NSString
    let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
    return newString.length <= maxLength
}

1
Câu trả lời tốt. Đánh giá cao.
Hasya

Cảm ơn bạn @Hasya
Pavlos


6

Tôi nghĩ rằng phần mở rộng tiện dụng hơn cho việc này. Xem câu trả lời đầy đủ tại đây

private var maxLengths = [UITextField: Int]()

// 2
extension UITextField {

  // 3
  @IBInspectable var maxLength: Int {
    get {
      // 4
      guard let length = maxLengths[self] else {
        return Int.max
      }
      return length
    }
    set {
      maxLengths[self] = newValue
      // 5
      addTarget(
        self,
        action: #selector(limitLength),
        forControlEvents: UIControlEvents.EditingChanged
      )
    }
  }

  func limitLength(textField: UITextField) {
    // 6
    guard let prospectiveText = textField.text
      where prospectiveText.characters.count > maxLength else {
        return
    }

    let selection = selectedTextRange
    // 7
    text = prospectiveText.substringWithRange(
      Range<String.Index>(prospectiveText.startIndex ..< prospectiveText.startIndex.advancedBy(maxLength))
    )
    selectedTextRange = selection
  }

}

4

Các giải pháp khác được đăng ở trên tạo ra một chu kỳ lưu giữ do bản đồ trường văn bản. Bên cạnh đó, thuộc maxLengthtính nên vô hiệu nếu không được đặt thay vì các Int.maxcông trình nhân tạo ; và mục tiêu sẽ được đặt nhiều lần nếu maxLength được thay đổi.

Đây là giải pháp cập nhật cho Swift4 với bản đồ yếu để ngăn rò rỉ bộ nhớ và các bản sửa lỗi khác

private var maxLengths = NSMapTable<UITextField, NSNumber>(keyOptions: NSPointerFunctions.Options.weakMemory, valueOptions: NSPointerFunctions.Options.strongMemory)

extension UITextField {

    var maxLength: Int? {
        get {
            return maxLengths.object(forKey: self)?.intValue
        }
        set {
            removeTarget(self, action: #selector(limitLength), for: .editingChanged)
            if let newValue = newValue {
                maxLengths.setObject(NSNumber(value: newValue), forKey: self)
                addTarget(self, action: #selector(limitLength), for: .editingChanged)
            } else {
                maxLengths.removeObject(forKey: self)
            }
        }
    }

    @IBInspectable var maxLengthInspectable: Int {
        get {
            return maxLength ?? Int.max
        }
        set {
            maxLength = newValue
        }
    }

    @objc private func limitLength(_ textField: UITextField) {
        guard let maxLength = maxLength, let prospectiveText = textField.text, prospectiveText.count > maxLength else {
            return
        }
        let selection = selectedTextRange
        text = String(prospectiveText[..<prospectiveText.index(from: maxLength)])
        selectedTextRange = selection
    }
}

Cảm ơn câu trả lời của bạn, Bạn có thể giải thích maxLengths được không?
Keyhan Kamangar

3

Giải pháp đơn giản mà không cần sử dụng đại biểu:

TEXT_FIELD.addTarget(self, action: #selector(editingChanged(sender:)), for: .editingChanged)


@objc private func editingChanged(sender: UITextField) {

        if let text = sender.text, text.count >= MAX_LENGHT {
            sender.text = String(text.dropLast(text.count - MAX_LENGHT))
            return
        }
}

2
Câu trả lời Tôi đang tìm kiếm: D
Ankur Lahiry Nhà

1
Đây là giải pháp, đơn giản và thanh lịch, không có mã soạn sẵn.
zeeshan

3

Phiên bản Swift 4 của tôi shouldChangeCharactersIn

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

        guard let preText = textField.text as NSString?,
            preText.replacingCharacters(in: range, with: string).count <= MAX_TEXT_LENGTH else {
            return false
        }

        return true
    }

Đây phải là câu trả lời được chấp nhận. Hoạt động hoàn hảo, không có lỗi.
10623169

2

Tôi có điều gì đó để thêm vào câu trả lời của Aladin:

  1. Bộ điều khiển chế độ xem của bạn phải tuân theo UITextFieldDelegate

    class MyViewController: UIViewController, UITextViewDelegate {
    
    }
    
  2. Đặt người đại diện cho trường văn bản của bạn: Để đặt người đại diện, bạn có thể điều khiển kéo từ trường văn bản đến bộ điều khiển chế độ xem của bạn trong bảng phân cảnh. Tôi nghĩ điều này tốt hơn là đặt nó trong mã

  3. Triển khai phương pháp trong bộ điều khiển chế độ xem của bạn: textField(_:shouldChangeCharactersInRange:replacementString:)


2

Tôi đưa ra một câu trả lời bổ sung dựa trên @Frouo. Tôi nghĩ câu trả lời của anh ấy là cách đẹp nhất. Trở thành một điều khiển chung mà chúng ta có thể sử dụng lại. Và không có vấn đề rò rỉ ở đây.

    private var kAssociationKeyMaxLength: Int = 0

    extension UITextField {

        @IBInspectable var maxLength: Int {
            get {
                if let length = objc_getAssociatedObject(self, &kAssociationKeyMaxLength) as? Int {
                    return length
                } else {
                    return Int.max
                }
            }
            set {
                objc_setAssociatedObject(self, &kAssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN)
                self.addTarget(self, action: #selector(checkMaxLength), for: .editingChanged)
            }
        }

//The method is used to cancel the check when use Chinese Pinyin input method.
        //Becuase the alphabet also appears in the textfield when inputting, we should cancel the check.
        func isInputMethod() -> Bool {
            if let positionRange = self.markedTextRange {
                if let _ = self.position(from: positionRange.start, offset: 0) {
                    return true
                }
            }
            return false
        }


        func checkMaxLength(textField: UITextField) {

            guard !self.isInputMethod(), let prospectiveText = self.text,
                prospectiveText.count > maxLength
                else {
                    return
            }

            let selection = selectedTextRange
            let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
            text = prospectiveText.substring(to: maxCharIndex)
            selectedTextRange = selection
        }



    }

2

cập nhật cho câu trả lời Fattie này

cảm ơn

extension UITextField {

    /// Runtime key
    private struct AssociatedKeys {
        /// max lenght key
        static var maxlength: UInt8 = 0
        /// temp string key
        static var tempString: UInt8 = 0
    }

    /// Limit the maximum input length of the textfiled
    @IBInspectable var maxLength: Int {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.maxlength) as? Int ?? 0
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.maxlength, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            addTarget(self, action: #selector(handleEditingChanged(textField:)), for: .editingChanged)
        }
    }

    /// temp string
    private var tempString: String? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.tempString) as? String
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.tempString, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    /// When the text changes, process the amount of text in the input box so that its length is within the controllable range.
    @objc private func handleEditingChanged(textField: UITextField) {

        /// Special Processing for Chinese Input Method
        guard markedTextRange == nil else { return }

        if textField.text?.count == maxLength {

            /// SET lastQualifiedString where text length == max lenght
            tempString = textField.text
        } else if textField.text?.count ?? 0 < maxLength {

            /// clear lastQualifiedString when text lengeht > maxlength
            tempString = nil
        }

        /// keep current text range in arcgives
        let archivesEditRange: UITextRange?

        if textField.text?.count ?? 0 > maxLength {

            /// if text length > maxlength,remove last range,to move to -1 postion.
            let position = textField.position(from: safeTextPosition(selectedTextRange?.start), offset: -1) ?? textField.endOfDocument
            archivesEditRange = textField.textRange(from: safeTextPosition(position), to: safeTextPosition(position))
        } else {

            /// just set current select text range
            archivesEditRange = selectedTextRange
        }

        /// main handle string max length
        textField.text = tempString ?? String((textField.text ?? "").prefix(maxLength))

        /// last config edit text range
        textField.selectedTextRange = archivesEditRange
    }

    /// get safe textPosition
    private func safeTextPosition(_ optionlTextPosition: UITextPosition?) -> UITextPosition {

        /* beginningOfDocument -> The end of the the text document. */
        return optionlTextPosition ?? endOfDocument
    }
}

1

Làm việc trong Swift4

// BƯỚC 1 đặt UITextFieldDelegate

    class SignUPViewController: UIViewController , UITextFieldDelegate {

       @IBOutlet weak var userMobileNoTextFiled: UITextField!

        override func viewDidLoad() {
            super.viewDidLoad()

// BƯỚC 2 đặt ủy quyền
userMobileNoTextFiled.delegate = self // đặt ủy quyền}

     func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    //        guard let text = userMobileNoTextFiled.text else { return true }
    //        let newLength = text.count + string.count - range.length
    //        return newLength <= 10
    //    }

// BƯỚC 3 gọi func

        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            let maxLength = 10          // set your need
            let currentString: NSString = textField.text! as NSString
            let newString: NSString =
                currentString.replacingCharacters(in: range, with: string) as NSString
            return newString.length <= maxLength
        }
    }

1

Câu trả lời này dành cho Swift 4 và khá dễ hiểu với khả năng cho phép xóa lùi.

func textField(_ textField: UITextField, 
               shouldChangeCharactersIn range: NSRange, 
               replacementString string: String) -> Bool {
    return textField.text!.count < 10 || string == ""
}

Điều này không xử lý sao chép và dán
ngô

1

Đơn giản chỉ cần kiểm tra số ký tự trong chuỗi

  1. Thêm một đại biểu để xem bộ điều khiển ans asign ủy quyền
    class YorsClassName : UITextFieldDelegate {

    }
  1. kiểm tra số lượng ký tự được phép cho trường văn bản
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    if textField.text?.count == 1 {
        return false
    }
    return true
}

Lưu ý: Ở đây tôi đã kiểm tra chỉ char được phép trong textField


1

Ký tự giới hạn trường văn bản sau khi chặn văn bản trong Swift 4

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


    if textField == self.txtDescription {
        let maxLength = 200
        let currentString: NSString = textField.text! as NSString
        let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
        return newString.length <= maxLength
    }

    return true


}

1

Trong trường hợp, đừng quên bảo vệ kích thước phạm vi trước khi áp dụng nó vào chuỗi. Nếu không, bạn sẽ gặp sự cố nếu người dùng làm điều này:

Nhập văn bản có độ dài tối đa Chèn một cái gì đó (Không có gì sẽ được chèn do giới hạn độ dài, nhưng iOS không biết về điều đó) Hoàn tác chèn (Bạn gặp sự cố, phạm vi nguyên nhân sẽ lớn hơn kích thước chuỗi thực tế)

Ngoài ra, sử dụng iOS 13, người dùng có thể vô tình kích hoạt điều này bằng cử chỉ

Tôi đề nghị bạn thêm vào dự án của bạn cái này

extension String {
    func replace(with text: String, in range: NSRange) -> String? {
        guard range.location + range.length <= self.count else { return nil }
        return (self as NSString).replacingCharacters(in: range, with: text)
    }
}

Và sử dụng nó như thế này:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    guard let newText = textView.text.replace(with: text, in: range) else { return false }
    return newText.count < maxNumberOfCharacters
}

Nếu không, bạn sẽ liên tục gặp sự cố trong ứng dụng của mình


0

Đây là một thay thế Swift 3.2+ tránh thao tác chuỗi không cần thiết. Trong trường hợp này, độ dài tối đa là 10:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let text = textField.text ?? ""

    return text.count - range.length + string.count <= 10
}

0

Tôi sử dụng bước này, đầu tiên Đặt texfield ủy quyền trong viewdidload.

    override func viewDidLoad() {
        super.viewDidLoad()

        textfield.delegate = self

    }

và sau đó shouldChangeCharactersIn sau khi bạn bao gồm UITextFieldDelegate.

extension viewController: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
                let newLength = (textField.text?.utf16.count)! + string.utf16.count - range.length
                if newLength <= 8 { 
                    return true
                } else {
                    return false
                }
            }
    }

0

Nếu bạn có nhiều Trường văn bản có các kiểm tra độ dài khác nhau trên một trang, tôi đã tìm thấy một giải pháp dễ dàng và ngắn gọn.

class MultipleTextField: UIViewController {

    let MAX_LENGTH_TEXTFIELD_A = 10
    let MAX_LENGTH_TEXTFIELD_B = 11

    lazy var textFieldA: UITextField = {
        let textField = UITextField()
        textField.tag = MAX_LENGTH_TEXTFIELD_A
        textField.delegate = self
        return textField
    }()
    lazy var textFieldB: UITextField = {
        let textField = UITextField()
        textField.tag = MAX_LENGTH_TEXTFIELD_B
        textField.delegate = self
        return textField
    }()
}

extension MultipleTextField: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        return (range.location < textField.tag) && (string.count < textField.tag)
    }
}
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.