Je sais qu'il y a d'autres sujets à ce sujet mais je n'arrive pas à trouver comment le mettre en œuvre.
J'essaie de limiter un UITextField à 5 caractères.
De préférence alphanumérique et - et. et _
J'ai vu ce code
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
}
et
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
}
Je ne sais tout simplement pas comment le mettre en œuvre ni quel "champ de texte" dois-je échanger contre mon programme personnalisé nommé UITextField
Votre contrôleur de vue doit être conforme à UITextFieldDelegate
, comme ci-dessous:
class MyViewController: UIViewController, UITextFieldDelegate {
}
Définissez le délégué de votre champ de texte: myTextField.delegate = self
textField(_:shouldChangeCharactersInRange:replacementString:)
Tous ensemble:
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
}
Pour 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
}
Ne permettre la saisie que d'un ensemble de caractères spécifié dans un champ de texte donné
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
}
Veillez à ce que une grande partie de l’exemple de code que vous verrez en ligne concernant ce problème soit très obsolète}.
Il vous suffit de coller les éléments suivants dans n’importe quel fichier Swift de votre projet. Nommez le fichier, par exemple, "Handy.Swift"
Vos champs de texte ont maintenant un .maxLength
.
Il est tout à fait correct de définir cette valeur dans le storyboard lors du développement ou de la définir dans le code pendant l'exécution de l'application.
// 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?.safelyLimitedTo(length: maxLength)
}
}
extension String
{
func safelyLimitedTo(length n: Int)->String {
if (self.count <= n) {
return self
}
return String( Array(self).prefix(upTo: n) )
}
}
C'est si simple.
(Remarque: "overseasLimitedTo # length" est simplement un appel qui réduit la longueur d'une chaîne. Tous les programmeurs Swift ont leur propre extension pour cela, ou, utilisez simplement le mien que vous voyez ici.)
La solution ci-dessus corrige les tous champs de texte de votre projet.
Si vous voulez juste que un champ de texte particulier soit simplement limité à "4", c'est tout ...
class PinCodeEntry: UITextField {
override func didMoveToSuperview() {
super.didMoveToSuperview()
addTarget(self, action: #selector(fixMe), for: .editingChanged)
}
@objc private func fixMe() { text = text?.safelyLimitedTo(length 4) }
}
Phew! C'est tout ce qu'on peut en dire.
(Just BTW, voici une astuce très utile similaire concernant UITextView, https://stackoverflow.com/a/42333832/294884 )
Swift 4, utilisez simplement:
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return range.location < 10
}
De la même manière que Steven Schmatz l’a fait, mais avec 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
}
Je pense que l'extension est plus pratique pour cela. Voir la réponse complète ici
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
}
}
Les autres solutions présentées ci-dessus produisent un cycle de conservation en raison de la carte de champ de texte. En outre, la propriété maxLength
devrait être nullable si elle n'est pas définie à la place des constructions Int.max
artificielles; et la cible sera définie plusieurs fois si maxLength est modifié.
Voici une solution mise à jour pour Swift4 avec une carte faible pour éviter les fuites de mémoire et les autres correctifs
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
}
}
Ma version Swift 4 de 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
}
Cette réponse est pour Swift 4, et est assez simple avec la possibilité de laisser un retour en arrière.
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
return textField.text!.count < 10 || string == ""
}
J'ai quelque chose à ajouter à la réponse d'Aladin:
Votre contrôleur de vue doit être conforme à UITextFieldDelegate
class MyViewController: UIViewController, UITextViewDelegate {
}
Définissez le délégué de votre champ de texte: Pour définir le délégué, vous pouvez contrôler le glissement du champ de texte vers votre contrôleur de vue dans le storyboard. Je pense que cela est préférable à le mettre en code
Implémentez la méthode dans votre contrôleur de vue: textField(_:shouldChangeCharactersInRange:replacementString:)
Je donne une réponse complémentaire basée sur @Frouo. Je pense que sa réponse est la plus belle façon. Parce que c'est un contrôle commun que nous pouvons réutiliser. Et il n'y a pas de problème de fuite ici.
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
}
}
mise à jour pour cette Fattie answer
import UIKit
extension UITextField {
/// Runtime 键
private struct AssociatedKeys {
static var maxlength: UInt8 = 0
static var lastString: UInt8 = 0
}
/// 最大输入长度
@IBInspectable var maxLength: Int {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.maxlength) as? Int ?? 0
}
set(newValue) {
objc_setAssociatedObject(self, &AssociatedKeys.maxlength, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
addTarget(self, action: #selector(fix), for: .editingChanged)
}
}
/// 最后一个符合条件的规则
private var lastQualifiedString: String? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.lastString) as? String
}
set(newValue) {
objc_setAssociatedObject(self, &AssociatedKeys.lastString, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
@objc func fix(textField: UITextField) {
guard markedTextRange == nil else { return }
/// 如果 个数 为最大个数
/// 在字典中,保存 最大数据
if textField.text?.count == maxLength {
/// 在 字典中保存 该数值
lastQualifiedString = textField.text
// 在 小于个数时 清除 数据
} else if textField.text?.count ?? 0 < maxLength {
lastQualifiedString = nil
}
let editRange: UITextRange?
/// 如果 输入框内的个数大于 最大值
if textField.text?.count ?? 0 > maxLength {
/// 将选中的 range 向前移动一个位置
let position = textField.position(from: safeTextPosition(selectedTextRange?.start), offset: -1) ?? textField.beginningOfDocument
editRange = textField.textRange(from: safeTextPosition(position), to: safeTextPosition(position))
} else {
editRange = selectedTextRange
}
/// 配置 值
textField.text = textField.text?.safelyLimitedTo(length: maxLength, safeText: lastQualifiedString)
textField.selectedTextRange = editRange
}
/// 安全获取 UITextPosition
private func safeTextPosition(_ optionlTextPosition: UITextPosition?) -> UITextPosition {
/* beginningOfDocument -> The end and beginning of the the text document. */
return optionlTextPosition ?? self.beginningOfDocument
}
}
extension String {
/// 比较后 决定 返回 text 还是 safetext
///
/// - Parameters:
/// - n: 长度
/// - safeText: 安全字符串
/// - Returns: 返回的值
fileprivate func safelyLimitedTo(length n: Int, safeText: String?) -> String? {
if (self.count <= n) {
return self
}
return safeText ?? String( Array(self).prefix(upTo: n) )
}
}
Travailler chez Swift4
// STEP 1 set UITextFieldDelegate
class SignUPViewController: UIViewController , UITextFieldDelegate {
@IBOutlet weak var userMobileNoTextFiled: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// délégué STEP 2
userMobileNoTextFiled.delegate = self // Définition du délégué }
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
// }
// STEP 3 call 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
}
}
Solution simple sans utiliser de délégué:
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
}
}
Voici une alternative à Swift 3.2+ qui évite les manipulations inutiles de chaînes. Dans ce cas, la longueur maximale est de 10:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let text = textField.text ?? ""
return text.count - range.length + string.count <= 10
}
J'utilise cette étape, d'abord Définir délégué texfield dans viewdidload.
override func viewDidLoad() {
super.viewDidLoad()
textfield.delegate = self
}
puis shouldChangeCharactersIn après l’inclusion de 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
}
}
}
Il suffit simplement de vérifier avec le nombre de caractères dans la chaîne
class YorsClassName: UITextFieldDelegate {
}
func textField (_ textField: UITextField, shouldChangeCharactersIn gamme: NSRange, replacementString string: String) -> Bool {si textField.text? .count == 1 {return false} return true}
Note: Ici, je n'ai vérifié que les caractères autorisés dans textField.