Wiem, że są inne tematy na ten temat, ale nie mogę się dowiedzieć, jak to wdrożyć.
Próbuję ograniczyć UITextField do tylko 5 znaków
Najlepiej alfanumeryczne i - i. i _
Widziałem ten kod
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
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
}
Po prostu nie wiem, jak to właściwie zaimplementować lub które „pole tekstowe” należy zamienić na moje niestandardowe pole o nazwie UITextField
String
w Swift te dni można w końcu po prostu .prefix (n)Odpowiedzi:
Twój kontroler widoku powinien być zgodny z
UITextFieldDelegate
, jak poniżej:class MyViewController: UIViewController, UITextFieldDelegate { }
Ustaw delegata swojego pola tekstowego:
myTextField.delegate = self
Zaimplementuj metodę w kontrolerze widoku:
textField(_:shouldChangeCharactersInRange:replacementString:)
Wszyscy razem:
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 }
Dla 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 }
Umożliwienie wpisania tylko określonego zestawu znaków w dane pole tekstowe
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 }
Jak zaprogramować pole tekstowe iOS, które przyjmuje tylko dane liczbowe o maksymalnej długości
źródło
textField
w metodziefunc textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
shouldChangeCharactersInRange
jest callback , to dla wszystkich pól tekstowych, otrzymujesz callback w tym samym miejscushouldChangeCharactersInRange
i wewnątrz tej metody możesz wiedzieć, które pole tekstowe jest edytowane dzięki przekazanemu parametrowi,textField
który możesz na przykład nadać tag dla każdego pola tekstowego i przetestuj wewnątrz,shouldChangeCharactersInRange
a dla każdego pola tekstowego przeprowadź walidację zawartościGrudnia 2017. Swift 4.
Uważaj, aby przykładowy kod, który zobaczysz w Internecie dotyczący tego problemu, jest bardzo nieaktualny .
Wklej poniższe do dowolnego pliku Swift w swoim projekcie. Możesz dowolnie nazwać plik, na przykład „Handy.swift”
To w końcu rozwiązuje jeden z najgłupszych problemów w iOS:
Twoje pola tekstowe mają teraz rozszerzenie
.maxLength
.Całkowicie w porządku jest ustawić tę wartość w scenorysie podczas programowania lub ustawić ją w kodzie, gdy aplikacja jest uruchomiona.
// 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) } }
To takie proste.
Przypis - w dzisiejszych czasach, aby bezpiecznie skrócić a
String
szybko, po prostu.prefix(n)
Jeszcze prostsza jednorazowa wersja ...
Powyższe rozwiązuje wszystkie pola tekstowe w projekcie.
Jeśli chcesz, aby jedno konkretne pole tekstowe było ograniczone do „4”, to jest to ...
class PinCodeEntry: UITextField { override func didMoveToSuperview() { super.didMoveToSuperview() addTarget(self, action: #selector(fixMe), for: .editingChanged) } @objc private func fixMe() { text = text?.prefix(4) } }
Uff! To wszystko.
(Tak przy okazji, oto podobna bardzo przydatna wskazówka dotycząca widoku UIText , https://stackoverflow.com/a/42333832/294884 )
Dla programisty OCD (jak ja) ...
Jak przypomina @LeoDabus, .prefix zwraca podciąg. Jeśli jesteś niesamowicie troskliwy, to
let t = textField.text textField.text = t?.prefix(maxLength)
byłoby
if let t: String = textField.text { textField.text = String(t.prefix(maxLength)) }
Cieszyć się!
źródło
Swift 4, po prostu użyj:
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { return range.location < 10 }
źródło
string.count < MAX_LENGTH
W ten sam sposób zrobił to Steven Schmatz, ale używając 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 }
źródło
Dla Swift 5: po
prostu napisz jedną linię, aby ustawić maksymalną długość znaku:
self.textField.maxLength = 10
Aby uzyskać więcej informacji, kliknij tutaj
Źródło: http://www.swiftdevcenter.com/max-character-limit-of-uitextfield-and-allowed-characters-swift/
źródło
Myślę, że rozszerzenie jest do tego bardziej przydatne. Zobacz pełną odpowiedź tutaj
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 } }
źródło
Inne rozwiązania zamieszczone powyżej powodują cykl przechowywania ze względu na mapę tekstową. Poza tym
maxLength
właściwość powinna mieć wartość null, jeśli nie jest ustawiona zamiast sztucznychInt.max
konstrukcji; a cel zostanie ustawiony wiele razy, jeśli zmienisz maxLength.Tutaj zaktualizowane rozwiązanie dla Swift4 ze słabą mapą, aby zapobiec wyciekom pamięci i innym poprawkom
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 } }
źródło
Proste rozwiązanie bez użycia pełnomocnika:
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 } }
źródło
Moja wersja Swift 4
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 }
źródło
Mam coś do dodania do odpowiedzi Aladina:
Twój kontroler widoku powinien być zgodny z
UITextFieldDelegate
class MyViewController: UIViewController, UITextViewDelegate { }
Ustaw delegata swojego pola tekstowego: Aby ustawić pełnomocnika, możesz kontrolować przeciąganie z pola tekstowego do kontrolera widoku w scenorysie. Myślę, że jest to lepsze niż ustawienie go w kodzie
Zaimplementuj metodę w kontrolerze widoku:
textField(_:shouldChangeCharactersInRange:replacementString:)
źródło
Uzupełniającą odpowiedź udzielam na podstawie @Frouo. Myślę, że jego odpowiedź jest najpiękniejsza. Ponieważ jest to powszechna kontrola, którą możemy ponownie wykorzystać. I tutaj nie ma problemu z wyciekiem.
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 } }
źródło
aktualizacja dla tej odpowiedzi Fattie
dzięki
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 } }
źródło
Praca w Swift4
// KROK 1 ustaw UITextFieldDelegate
class SignUPViewController: UIViewController , UITextFieldDelegate { @IBOutlet weak var userMobileNoTextFiled: UITextField! override func viewDidLoad() { super.viewDidLoad()
// KROK 2 ustaw delegata
userMobileNoTextFiled.delegate = self // ustaw delegata}
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 // }
// wywołanie funkcji KROKU 3
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 } }
źródło
Ta odpowiedź dotyczy Swift 4 i jest dość prosta z możliwością przepuszczenia cofnięcia.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { return textField.text!.count < 10 || string == "" }
źródło
Po prostu sprawdź liczbę znaków w ciągu
class YorsClassName : UITextFieldDelegate { }
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if textField.text?.count == 1 { return false } return true }
Uwaga: tutaj sprawdziłem, czy w textField jest tylko znak dozwolony
źródło
TextField Limit Character After Block the Text in 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 }
źródło
Na wszelki wypadek nie zapomnij zabezpieczyć rozmiaru zakresu przed zastosowaniem go do łańcucha. W przeciwnym razie nastąpi awaria, jeśli użytkownik to zrobi:
Wpisz tekst o maksymalnej długości Wstaw coś (Nic nie zostanie wstawione z powodu ograniczenia długości, ale iOS o tym nie wie) Cofnij wstawienie (Wystąpi awaria, ponieważ zakres będzie większy niż rzeczywisty rozmiar ciągu)
Ponadto użytkownicy iOS 13 mogą przypadkowo wywołać to za pomocą gestów
Proponuję dodać to do swojego projektu
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) } }
I użyj tego w ten sposób:
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 }
W przeciwnym razie aplikacja będzie się ciągle zawieszać
źródło
Oto alternatywa dla Swift 3.2+, która pozwala uniknąć niepotrzebnych manipulacji na strunach. W takim przypadku maksymalna długość to 10:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let text = textField.text ?? "" return text.count - range.length + string.count <= 10 }
źródło
Używam tego kroku, najpierw Ustaw delegata texfield w viewdidload.
override func viewDidLoad() { super.viewDidLoad() textfield.delegate = self }
a następnie shouldChangeCharactersIn po uwzględnieniu 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 } } }
źródło
Jeśli masz wiele pól textField, które mają różne kontrole długości na jednej stronie, znalazłem łatwe i krótkie rozwiązanie.
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) } }
źródło