Maksymalna długość UITextField

120

Kiedy próbowałem Jak ustawić maksymalną liczbę znaków, które można wprowadzić do UITextField za pomocą swift? , Widziałem, że jeśli użyję wszystkich 10 znaków, nie mogę też usunąć znaku.

Jedyne, co mogę zrobić, to anulować operację (usunąć wszystkie znaki razem).

Czy ktoś wie, jak nie blokować klawiatury (żebym nie mógł dodawać innych liter / symboli / cyfr, ale mogę użyć backspace)?

Giorgio Nocera
źródło

Odpowiedzi:

295

W przypadku Swift 5 i iOS 12 wypróbuj następującą implementację textField(_:shouldChangeCharactersIn:replacementString:)metody, która jest częścią UITextFieldDelegateprotokołu:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard let textFieldText = textField.text,
        let rangeOfTextToReplace = Range(range, in: textFieldText) else {
            return false
    }
    let substringToReplace = textFieldText[rangeOfTextToReplace]
    let count = textFieldText.count - substringToReplace.count + string.count
    return count <= 10
}
  • Najważniejszą częścią tego kodu jest konwersja z range( NSRange) na rangeOfTextToReplace( Range<String.Index>). Obejrzyj ten samouczek wideo, aby zrozumieć, dlaczego ta konwersja jest ważna.
  • Aby to działało poprawnie kod, należy również ustawić textField„s smartInsertDeleteTypewartości UITextSmartInsertDeleteType.no. Zapobiegnie to ewentualnemu wstawieniu (niechcianej) dodatkowej przestrzeni podczas wykonywania operacji wklejania.

Pełny przykładowy kod poniżej pokazuje, jak zaimplementować textField(_:shouldChangeCharactersIn:replacementString:)w UIViewController:

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var textField: UITextField! // Link this to a UITextField in Storyboard

    override func viewDidLoad() {
        super.viewDidLoad()

        textField.smartInsertDeleteType = UITextSmartInsertDeleteType.no
        textField.delegate = self
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        guard let textFieldText = textField.text,
            let rangeOfTextToReplace = Range(range, in: textFieldText) else {
                return false
        }
        let substringToReplace = textFieldText[rangeOfTextToReplace]
        let count = textFieldText.count - substringToReplace.count + string.count
        return count <= 10
    }

}
Imanou Petit
źródło
Czy po prostu umieszczasz ten kod w swojej klasie kontrolera widoku? Czy muszę nawiązywać połączenia?
Isaac Wasserman
Jeśli ktoś potrzebuje postawić jakiś warunek… możesz to zrobić…. if (textField .isEqual (mobileNumberTextfield)) {guard let text = textField.text else {return true} let newLength = text.characters.count + string.characters.count - range.length return newLength <= limitLength; } return true;
Narasimha Nallamsetty
6
W przypadku Swift 4 text.characters.countjest przestarzałetext.count
Mohamed Salah
47

Robię to tak:

func checkMaxLength(textField: UITextField!, maxLength: Int) {
    if (countElements(textField.text!) > maxLength) {
        textField.deleteBackward()
    }
}

Kod działa dla mnie. Ale pracuję z storyboardem. W Storyboard dodaję akcję dla pola tekstowego w kontrolerze widoku przy zmianie edycji .

Jaskółka oknówka
źródło
1
Funkcja countElements została zmieniona, aby liczyć w Swift 2, ale zmiana to działa dla mnie!
John
1
Dzięki, możesz teraz użyć textField.text? .Characters.count od czasu zmiany countElements.
Anibal R.,
1
Tks, działało świetnie z tą zmianą: countElements (textField.text!) W Swift 2 to: textField.text? .Characters.count
kha
33

Aktualizacja dla Swift 4

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
     guard let text = textField.text else { return true }
     let newLength = text.count + string.count - range.length
     return newLength <= 10
}
Shan Ye
źródło
15

Dodaj więcej szczegółów z odpowiedzi @Martin

// linked your button here
@IBAction func mobileTFChanged(sender: AnyObject) {
    checkMaxLength(sender as! UITextField, maxLength: 10)
}

// linked your button here
@IBAction func citizenTFChanged(sender: AnyObject) {
    checkMaxLength(sender as! UITextField, maxLength: 13)
}

func checkMaxLength(textField: UITextField!, maxLength: Int) {
    // swift 1.0
    //if (count(textField.text!) > maxLength) {
    //    textField.deleteBackward()
    //}
    // swift 2.0
    if (textField.text!.characters.count > maxLength) {
        textField.deleteBackward()
    }
}
Sruit A.Suk
źródło
1
count (textField.text!) zwraca błąd. Musisz użyć textField.text! .Characters.count
Regis St-Gelais
1
Dzięki @ RegisSt-Gelais, to już stara odpowiedź, zaktualizowałem ją teraz
Sruit A.Suk
11

W Swift 4

Ograniczenie do 10 znaków dla pola tekstowego i zezwolenie na usuwanie (backspace)

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if textField ==  userNameFTF{
            let char = string.cString(using: String.Encoding.utf8)
            let isBackSpace = strcmp(char, "\\b")
            if isBackSpace == -92 {
                return true
            }
            return textField.text!.count <= 9
        }
        return true
    }
Sai kumar Reddy
źródło
8
func checkMaxLength(textField: UITextField!, maxLength: Int) {
        if (textField.text!.characters.count > maxLength) {
            textField.deleteBackward()
        }
}

mała zmiana dla IOS 9

Jeremy Andrews
źródło
8

Szybki 3

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

            let nsString = NSString(string: textField.text!)
            let newText = nsString.replacingCharacters(in: range, with: string)
            return  newText.characters.count <= limitCount
    }
Basil Mariano
źródło
8

możesz rozszerzyć UITextField i dodać plik @IBInspectable obiekt do obsługi tego:

SWIFT 5

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)
        }
    }
    @objc func fix(textField: UITextField) {
        if let t = textField.text {
            textField.text = String(t.prefix(maxLength))
        }
    }
}

a następnie zdefiniuj go w inspektorze atrybutów

wprowadź opis obrazu tutaj

Zobacz oryginalną odpowiedź Swift 4

mohsen
źródło
2
Ładny, czysty kod. Ale z jakiegoś powodu powoduje to dziwne zachowanie podczas edycji, gdy używasz emoji. Przy każdej próbie edycji kursor przeskakuje do końca wiersza.
Phontaine Judd
5

Jeśli chcesz nadpisać ostatnią literę:

let maxLength = 10

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

    if range.location > maxLength - 1 {
        textField.text?.removeLast()
    }

    return true
}
maxwell
źródło
4

Opublikowałem rozwiązanie za pomocą IBInspectable, więc możesz zmienić wartość maksymalnej długości zarówno w kreatorze interfejsu, jak i programowo. Sprawdź to tutaj

frouo
źródło
3

Możesz użyć w Swift 5 lub Swift 4, jak obraz wygląda jak poniżej wprowadź opis obrazu tutaj

  1. Dodaj textField w kontrolerze widoku
  2. Połącz się z tekstem do ViewController
  3. dodaj kod w widoku ViewController

     class ViewController: UIViewController , UITextFieldDelegate {
    
      @IBOutlet weak var txtName: UITextField!
    
      var maxLen:Int = 8;
    
     override func viewDidLoad() {
        super.viewDidLoad()
    
        txtName.delegate = self
       }
    
     func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
         if(textField == txtName){
            let currentText = textField.text! + string
            return currentText.count <= maxLen
         }
    
         return true;
       }
    }

Możesz pobrać pełne źródło z GitHub: https://github.com/enamul95/TextFieldMaxLen

Enamul Haque
źródło
1

Uważaj na błąd cofania UITextField wspomniany w tym poście: Ustaw maksymalną długość znaków w UITextField

oto, jak szybko to naprawić

if(range.length + range.location > count(textField.text)) {
        return false;
}
Horatio
źródło
Jeśli chcesz wspierać emoji i takie użycie: if (range.length + range.location> count (textField.text.utf16)) {return false; }
AlexD
1
Here is my version of code. Hope it helps!

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        let invalidCharacters = NSCharacterSet(charactersInString: "0123456789").invertedSet

        if let range = string.rangeOfCharacterFromSet(invalidCharacters, options: nil, range:Range<String.Index>(start: string.startIndex, end: string.endIndex))
        {
            return false
        }

        if (count(textField.text) > 10  && range.length == 0)
        {
            self.view.makeToast(message: "Amount entry is limited to ten digits", duration: 0.5, position: HRToastPositionCenter)
            return false
        }
        else
        {

        }

        return true
    }
AG
źródło
1
Podoba mi się rozszerzenie Toast UIView :)
Regis St-Gelais
1

Używałem tego protokołu / rozszerzenia w jednej z moich aplikacji i jest trochę bardziej czytelny. Podoba mi się, jak rozpoznaje backspace i wyraźnie mówi ci, kiedy znak jest backspace.

Kilka kwestii do rozważenia:

Cokolwiek implementuje to rozszerzenie protokołu, musi określić limit znaków.Zwykle będzie to Twój ViewController, ale możesz zaimplementować limit znaków jako właściwość obliczoną i zwrócić coś innego, na przykład limit znaków w jednym z modeli.

2. Będziesz musiał wywołać tę metodę wewnątrz metody delegata shouldChangeCharactersInRange pola tekstowego. W przeciwnym razie nie będziesz w stanie zablokować wprowadzania tekstu, zwracając fałsz itp.

3. Prawdopodobnie będziesz chciał przepuścić znaki Backspace. Dlatego dodałem dodatkową funkcję do wykrywania backspace. Twoja metoda shouldChangeCharacters może to sprawdzić i wcześnie zwrócić wartość „true”, więc zawsze zezwalasz na cofanie.

protocol TextEntryCharacterLimited{
    var characterLimit:Int { get } 
}

extension TextEntryCharacterLimited{

    func charactersInTextField(textField:UITextField, willNotExceedCharacterLimitWithReplacementString string:String, range:NSRange) -> Bool{

        let startingLength = textField.text?.characters.count ?? 0
        let lengthToAdd = string.characters.count
        let lengthToReplace = range.length

        let newLength = startingLength + lengthToAdd - lengthToReplace

        return newLength <= characterLimit

    }

    func stringIsBackspaceWith(string:String, inRange range:NSRange) -> Bool{
        if range.length == 1 && string.characters.count == 0 { return true }
        return false
    }

}

Jeśli ktoś z was jest zainteresowany, mam repozytorium Github, w którym wykorzystałem niektóre z tego zachowania limitu znaków i umieściłem w strukturze iOS. Istnieje protokół, który możesz zaimplementować, aby uzyskać wyświetlacz limitu znaków podobny do Twittera, który pokazuje, jak daleko przekroczyłeś limit znaków.

CharacterLimited Framework w serwisie Github

Theo Bendixson
źródło
1

Ponieważ delegaci są relacją 1 do 1 i mógłbym chcieć użyć go gdzie indziej z innych powodów, chciałbym ograniczyć długość pola tekstowego, dodając ten kod w ich konfiguracji:

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        setup()
    }

    required override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    func setup() {

        // your setup...

        setMaxLength()
    }

    let maxLength = 10

    private func setMaxLength() {
            addTarget(self, action: #selector(textfieldChanged(_:)), for: UIControlEvents.editingChanged)
        }

        @objc private func textfieldChanged(_ textField: UITextField) {
            guard let text = text else { return }
            let trimmed = text.characters.prefix(maxLength)
            self.text = String(trimmed)

        }
MQLN
źródło
0

Używam tego;

Limit 3 znaków

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

        if let txt = textField.text {
            let currentText = txt + string
            if currentText.count > 3 {
                return false
            }
            return true
        }
        return true
    }
alicanozkara
źródło
0

Szybki 5

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let MAX_LENGTH = 4
        let updatedString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
        return updatedString.count <= MAX_LENGTH
    }
TDK
źródło
-3

Musisz sprawdzić, czy istniejący ciąg plus dane wejściowe jest większy niż 10.

   func textField(textField: UITextField!,shouldChangeCharactersInRange range: NSRange,    replacementString string: String!) -> Bool {
      NSUInteger newLength = textField.text.length + string.length - range.length;
      return !(newLength > 10)
   }
bhzag
źródło
5
Twój kod jest nieprawidłowy. 1. Musisz zadeklarować swoją stałą lub zmienną za pomocą let lub var w Swift (nie NSUInteger). 2. textField.text i string są typu String. Długość nie jest właściwością / metodą String w języku Swift.
Imanou Petit,