Swift'de bir UITextField için maksimum karakter uzunluğunu ayarlayın


88

Bununla ilgili başka konular olduğunu biliyorum ama nasıl uygulayacağımı bulamıyorum.

Bir UITextField'ı yalnızca 5 Karakterle sınırlamaya çalışıyorum

Tercihen Alfasayısal ve - ve. ve _

Bu kodu gördüm

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
}

ve

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 
}

Bunu gerçekten nasıl uygulayacağımı veya hangi "metin alanını" UITextField adlı özel adıma değiştirmem gerektiğini bilmiyorum



Hızlı uyarı - bu günlerde Swift'de a'yı kısaltmak için Stringnihayet sadece .prefix (n) yapabilirsiniz
Fattie

Yanıtlar:


136
  1. Görüntüleme denetleyiciniz UITextFieldDelegateaşağıdaki gibi uymalıdır :

    class MyViewController: UIViewController, UITextFieldDelegate {
    
    }
    
  2. Metin alanınızın temsilcisini ayarlayın: myTextField.delegate = self

  3. Yöntemi görünüm denetleyicinize uygulayın: textField(_:shouldChangeCharactersInRange:replacementString:)

Hep birlikte:

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
}

Swift 4 için

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
}

Belirli bir metin alanına yalnızca belirli bir karakter kümesinin girilmesine izin verme

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
}

Yalnızca maksimum uzunlukta sayısal girdi alan bir iOS metin alanı nasıl programlanır


Hızlı cevap için çok teşekkür ederim! Bu metin alanını temsilci olarak ayarlarsam, diğer metin alanlarını değiştirebilir miyim?
ishkur88

evet, ve ilk parametre olarak söz konusu textfield'ı (düzenlenmekte olan) alacak textFieldyönteminde func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
Aladin

Ama ikinci parametreyi nereye koymalıyım? Bir temsilci olarak ayarladıktan sonra myTextField'a tekrar başvurmuyorum.
ishkur88

Örneğin, 0-9 arası sadece telefon numaraları için başka bir metin alanı yapmak istersem.
ishkur88

bir metin alanı her düzenlendiğinde, geri arama shouldChangeCharactersInRangeçağrılır, bu tüm metin alanları içindir, geri aramayı aynı yerde alırsınız shouldChangeCharactersInRangeve bu yöntemde geçirilen parametre sayesinde hangi metin alanının düzenlendiğini textFieldbilirsiniz, örneğin bir her metin alanı için etiket ve her metin alanı için shouldChangeCharactersInRangeve her metin alanı için içeriğin doğrulamasını gerçekleştirin
Aladin

118

Modern Swift

O Not çevrimiçi bu sorunu ile ilgili örnek kod çok güncel son derece olduğu .

Aşağıdakini projenizdeki herhangi bir Swift dosyasına yapıştırın. (Dosyaya herhangi bir ad verebilirsiniz, örneğin "Handy.swift".)

Bu nihayet iOS'taki en aptalca sorunlardan birini düzeltir:

görüntü açıklamasını buraya girin

Metin alanlarınız artık bir .maxLength.

Geliştirme sırasında film şeridinde bu değeri ayarlamak veya uygulama çalışırken kodda ayarlamak tamamen tamamdır.

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

Bu kadar basit.


Dipnot - bu günlerde hızlıca güvenli bir şekilde kısaltmak için String,.prefix(n)


Daha da basit bir tek seferlik versiyon ...

Yukarıdakiler , projenizdeki tüm metin alanlarını düzeltir .

Yalnızca belirli bir metin alanının "4" ile sınırlandırılmasını istiyorsanız , işte bu ...

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

Vay be! Hepsi bu kadar.

(Sadece BTW, işte UIText Görünümü ile ilgili çok faydalı benzer bir ipucu , https://stackoverflow.com/a/42333832/294884 )


OKB programcısı için (benim gibi) ...

@LeoDabus'un hatırlattığı gibi, .prefixbir alt dize döndürür. İnanılmaz derecede önemsiyorsan, bu

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

olabilir

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

Zevk almak!


2
Mantıklı gibi! Teşekkür ederim.
J. Doe

13
Bu kadar yaygın ve çok basit bir şeye ulaşmak için tüm bunların yapılması gerektiği aklımı uçuruyor. Bize basit bir textField.maxLength yerleşik veremezler ... her neyse, çözümünüz harika, teşekkürler!
mylovemhz

1
Vay canına, SO hakkında sahip olduğum en iyi ipucu. Yapabilseydim 100 oy veririm!
jonathan3087

2
Çözüm kullanışlıdır ancak üstteki metin alanlarının haritası aslında bir tutma döngüsü oluşturacaktır.
Angel G. Olloqui

3
BU ÇÖZÜMÜ KULLANANLAR İÇİN UYARI! Bu çözümün bazı sorunları var. Bunlardan biri, eğer kullanıcı textField'in başına yazarsa, yeni karakteri yazmalarına izin vereceksiniz ve sonuncusu kaldırılacak, ayrıca imleç alandaki son karaktere atlayacaktır. Başka bir sorun da, metni programlı olarak ayarlarsanız, sınırdan daha büyük bir metin ayarlamanıza izin vermesidir. Bir değişikliği geri alırsanız (harici klavyeyle CMD + Z) başka bir sorun ortaya çıkar, daha önce sınırın üzerinde bir rakam eklemeye çalıştığınızda çökecektir.
juancazalla

25

Swift 4, sadece şunları kullanın:

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

bu seçilen cevap olmalıdır. Basit ve iyi çalışıyor.
user832

9
Çalışmıyor. Ya dizenin ortasına dokunursanız ve X karakterden fazlasını yazabilirsiniz.
Slavcho

range.location <10 yerine textField.text.length <10 kullanabilirsiniz. Bu çözüm basit ve zariftir.
Saqib Saud

Bu çözümü kullanabilirsiniz: eğer textField.text? .Count> = 12 {return false}
Armağan Билык

1
geçmiş eylemde çalışmak istiyorsanız eklemeniz gereken bir metni geçtiğinizde çalışmazstring.count < MAX_LENGTH
Reza Dehnavi

12

Steven Schmatz'ın yaptığı gibi Swift 3.0 kullanıyor:

//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
İyi cevap. Takdir edildi.
Hasya

Teşekkürler @Hasya
Pavlos

9

Swift 5 için:
Maksimum karakter uzunluğunu ayarlamak için sadece bir satır yazın:

 self.textField.maxLength = 10

Daha fazla ayrıntı için buraya tıklayın

Kredi: http://www.swiftdevcenter.com/max-character-limit-of-uitextfield-and-allowed-characters-swift/


Bu çözüm basit görünse de, aslında bunu uygulamak için gereken çok daha fazla kod var. Bu yanıt kendi başına pek yardımcı olmaz ve diğer ilgili kod parçalarının eklenmesi ve dahil edilmesi yardımcı olabilir.
FontFamily

6

Bence uzantı bunun için daha kullanışlı. Tam cevabı burada görün

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

Yukarıda yayınlanan diğer çözümler, metin alanı haritası nedeniyle bir tutma döngüsü oluşturur. Ayrıca, maxLengthözellik yapay Int.maxyapılar yerine null yapılabilir olmalıdır ; ve maxLength değiştirilirse hedef birden çok kez ayarlanacaktır.

Burada, bellek sızıntılarını ve diğer düzeltmeleri önlemek için zayıf bir haritayla Swift4 için güncellenmiş bir çözüm

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

Cevabınız için teşekkürler, maxLengths lütfen açıklayabilir misiniz?
Keyhan Kamangar

4

Temsilci kullanmadan basit çözüm:

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
Aradığım cevap: D
Ankur Lahiry

1
Bu, standart kod içermeyen, basit ve zarif bir çözümdür.
zeeshan

3

Swift 4 sürümüm 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
    }

Kabul edilen cevap bu olmalıdır. Hatasız, mükemmel çalışır.
10623169

2

Aladin'in cevabına eklemem gereken bir şey var:

  1. Görünüm denetleyiciniz aşağıdakilere uymalıdır: UITextFieldDelegate

    class MyViewController: UIViewController, UITextViewDelegate {
    
    }
    
  2. Metin alanınızın temsilcisini ayarlayın: Temsilciyi ayarlamak için, metin alanından film şeridindeki görünüm denetleyicinize sürüklemeyi kontrol edebilirsiniz. Sanırım bunu kod olarak ayarlamak daha tercih edilir

  3. Yöntemi görünüm denetleyicinize uygulayın: textField(_:shouldChangeCharactersInRange:replacementString:)


2

@ Frouo'ya dayalı ek bir cevap veriyorum. Bence cevabının en güzel yolu. Yeniden kullanabileceğimiz ortak bir kontrol olduğu için. Ve burada sızıntı sorunu yok.

    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

Sadece dizedeki karakter sayısını kontrol edin

  1. Denetleyiciyi ve bir temsilciyi görüntülemek için bir temsilci ekleyin
    class YorsClassName : UITextFieldDelegate {

    }
  1. metin alanı için izin verilen karakter sayısını kontrol edin
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    if textField.text?.count == 1 {
        return false
    }
    return true
}

Not: Burada yalnızca textField'da izin verilen karakterleri kontrol ettim


2

bu Fattie cevabı için güncelleme

Teşekkürler

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

Swift4'te Çalışma

// ADIM 1 set UITextFieldDelegate

    class SignUPViewController: UIViewController , UITextFieldDelegate {

       @IBOutlet weak var userMobileNoTextFiled: UITextField!

        override func viewDidLoad() {
            super.viewDidLoad()

// ADIM 2 delege
kullanıcıMobileNoTextFiled.delegate = self // delegeyi ayarla}

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

// ADIM 3 çağrı fonksiyonu

        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

Bu cevap Swift 4 içindir ve geri alma yeteneği ile oldukça basittir.

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

Bu, kopyalama ve yapıştırma işlemlerini gerçekleştirmez
cornr

1

Swift 4'te Metni Engelledikten Sonra Metin Alanı Sınırı Karakteri

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

Her ihtimale karşı, diziye uygulamadan önce aralık boyutunu korumayı unutmayın. Aksi takdirde, kullanıcı bunu yaparsa kilitlenme yaşarsınız:

Maksimum uzunluk metnini yazın Bir şey ekleyin (Uzunluk sınırlaması nedeniyle hiçbir şey eklenmeyecek, ancak iOS bunu bilmiyor) Eklemeyi geri al (Çökme yaşarsınız, neden aralığı gerçek dize boyutundan daha büyük olacaktır)

Ayrıca, iOS 13 kullanıcıları bunu yanlışlıkla hareketlerle tetikleyebilir

Bunu projenize eklemenizi öneririm

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

Ve bunu şu şekilde kullanın:

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
}

Aksi takdirde, uygulamanızda sürekli olarak kilitleneceksiniz


0

İşte gereksiz dizi manipülasyonunu önleyen bir Swift 3.2+ alternatifi. Bu durumda maksimum uzunluk 10'dur:

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

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

0

Bu adımı kullanıyorum, önce delege texfield'ı viewdidload'da ayarla.

    override func viewDidLoad() {
        super.viewDidLoad()

        textfield.delegate = self

    }

ve sonra UITextFieldDelegate'i ekledikten sonraChangeCharactersIn olmalıdır.

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

Bir sayfada çeşitli uzunluk kontrolleri olan birden fazla textField'iniz varsa, kolay ve kısa bir çözüm buldum.

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