Quand j'ai essayé Comment définir le nombre maximum de caractères pouvant être entrés dans un UITextField à l'aide de swift? , j'ai vu que si j'utilise tous les 10 caractères, je ne peux pas effacer le caractère aussi .
La seule chose que je peux faire est d'annuler l'opération (supprimer tous les caractères ensemble).
Est-ce que quelqu'un sait comment ne pas bloquer le clavier (pour que je ne puisse pas ajouter d'autres lettres/symboles/chiffres, mais que je puisse utiliser le retour arrière)?
Avec Swift 5 et iOS 12, essayez l'implémentation suivante de la méthode textField(_:shouldChangeCharactersIn:replacementString:)
qui fait partie du protocole UITextFieldDelegate
:
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
}
range
(NSRange
) en rangeOfTextToReplace
(Range<String.Index>
). Consultez ce didacticiel vidéo pour comprendre pourquoi cette conversion est importante.textField
smartInsertDeleteType
sur UITextSmartInsertDeleteType.no
. Cela empêchera l'insertion éventuelle d'un espace supplémentaire (non désiré) lors d'une opération de collage.L'exemple de code complet ci-dessous montre comment implémenter textField(_:shouldChangeCharactersIn:replacementString:)
dans un 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
}
}
Je le fais comme ça:
func checkMaxLength(textField: UITextField!, maxLength: Int) {
if (countElements(textField.text!) > maxLength) {
textField.deleteBackward()
}
}
Le code fonctionne pour moi. Mais je travaille avec le storyboard. Dans Storyboard, j'ajoute une action pour le champ de texte dans le contrôleur de vue sur modification modifiée.
Mise à jour pour 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
}
Ajouter plus de détails de la réponse @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()
}
}
func checkMaxLength(textField: UITextField!, maxLength: Int) {
if (textField.text!.characters.count > maxLength) {
textField.deleteBackward()
}
}
un petit changement pour IOS 9
Dans Swift 4
Limite de 10 caractères pour le champ de texte et permettre la suppression (retour arrière)
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
}
Swift
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
}
Si vous voulez écraser la dernière lettre:
let maxLength = 10
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if range.location > maxLength - 1 {
textField.text?.removeLast()
}
return true
}
J'ai posté une solution en utilisant IBInspectable
, afin que vous puissiez modifier la valeur de longueur maximale à la fois dans le générateur d'interface ou par programme. Check it out here
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
}
Puisque les délégués forment une relation un-à-un et que je pourrais l'utiliser ailleurs pour d'autres raisons, j'aime limiter la longueur du champ de texte en ajoutant ce code dans leur configuration:
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)
}
J'utilise ce protocole/cette extension dans l'une de mes applications et il est un peu plus lisible. J'aime la façon dont il reconnaît les espaces arrières et vous indique explicitement quand un personnage est un espace arrière.
Quelques points à considérer:
1.Quel que soit le type d'implémentation que cette extension de protocole nécessite de spécifier une limite de caractères. par exemple une limite de caractères sur l'un de vos modèles.
2. Vous devrez appeler cette méthode à l'intérieur de la méthode de délégation shouldChangeCharactersInRange de votre champ de texte. Sinon, vous ne pourrez pas bloquer la saisie de texte en renvoyant la valeur false, etc.
3. Vous voudrez probablement autoriser les caractères de retour arrière. C'est pourquoi j'ai ajouté la fonction supplémentaire permettant de détecter les espaces de retour. Votre méthode shouldChangeCharacters peut vérifier cela et renvoyer "true" au début afin de toujours autoriser les espaces de retour.
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
}
}
Si certains d'entre vous sont intéressés, j'ai un référentiel Github dans lequel j'ai pris un peu de ce comportement de limite de caractères et l'ai placé dans un cadre iOS. Il existe un protocole que vous pouvez implémenter pour obtenir un affichage de limite de caractères similaire à celui de Twitter qui indique jusqu'à quel point vous avez dépassé la limite de caractères.
Méfiez-vous du bogue d'annulation pour UITextField mentionné dans ce message: définir la longueur maximale de caractères d'un UITextField
voici comment résoudre ce problème dans Swift
if(range.length + range.location > count(textField.text)) {
return false;
}