SwiftでUITextFieldの最大文字長を設定します


88

これについては他にもトピックがあることは知っていますが、実装方法がわからないようです。

UITextFieldを5文字のみに制限しようとしています

できれば英数字と-および。および_

私はこのコードを見ました

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
}

そして

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 
}

実際に実装する方法や、UITextFieldという名前のカスタムと交換する必要がある「テキストフィールド」がわからないだけです。



クイックアラートが-する短縮Stringこのごろスウィフトにすることができます最終的にはちょうど.prefix(N)
Fattie

回答:


136
  1. ビューコントローラはUITextFieldDelegate、以下のように準拠している必要があります。

    class MyViewController: UIViewController, UITextFieldDelegate {
    
    }
    
  2. テキストフィールドのデリゲートを設定します。 myTextField.delegate = self

  3. ビューコントローラにメソッドを実装します。 textField(_:shouldChangeCharactersInRange:replacementString:)

すべて一緒に:

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
}

スイフト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
}

指定されたテキストフィールドに指定された文字セットのみを入力できるようにする

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
}

最大長の数値入力のみを受け取るiOSテキストフィールドをプログラムする方法


迅速な返信ありがとうございます!この1つのテキストフィールドをデリゲートとして設定した場合、他のテキストフィールドを変更できますか?
ishkur88 2015

はい。問題のテキストフィールド(編集中)textFieldがメソッドの 最初のパラメーターとして取得されますfunc textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
Aladin 2015

しかし、2番目のパラメーターはどこに入力しますか?myTextFieldをデリゲートとして設定した後は、再度参照しません。
ishkur88 2015

電話番号専用に別のテキストフィールド0〜9を作成したい場合のように。
ishkur88 2015

テキストフィールドが編集されるたびに、コールバックshouldChangeCharactersInRangeが呼び出されます。これはすべてのテキストフィールドに対してであり、同じ場所でコールバックを受け取ります。shouldChangeCharactersInRangeこのメソッド内では、渡されたパラメータのおかげで、どのテキストフィールドが編集されているかを知るtextFieldことができます。各テキストフィールドのタグと、shouldChangeCharactersInRangeおよび各テキストフィールド内のテストにより、コンテンツの検証が実行されます
Aladin 2015

118

モダンスイフト

この問題に関するオンラインのサンプルコードの多くは非常に古くなっていることに注意しください

以下をプロジェクトのSwiftファイルに貼り付けます。(たとえば、「Handy.swift」のように、ファイルに任意の名前を付けることができます。)

これにより、iOSで最も愚かな問題の1つが最終的に修正されます。

ここに画像の説明を入力してください

これで、テキストフィールドに .maxLength

開発中にストーリーボードにその値を設定することも、アプリの実行中にコードに設定することもまったく問題ありません。

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

とても簡単です。


脚注-最近、安全Stringに迅速に切り捨てるために、あなたは単に.prefix(n)


さらにシンプルな1回限りのバージョン...

上記はすべて修正しますは、プロジェクトのテキストフィールドをします。

1つの特定のテキストフィールドを単に「4」とだけに制限したい場合は、それだけです...

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

ふぅ!これですべてです。

(ところで、UITextビューに関連する同様の非常に便利なヒントがありますhttps: //stackoverflow.com/a/42333832/294884 )


OCDプログラマー(私のように)の場合...

@LeoDabusが思い出させるように.prefix、部分文字列を返します。あなたが信じられないほど気にかけているなら、これ

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

だろう

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

楽しい!


2
スジは通ってるようだ!ありがとうございました。
J. Doe 2017年

13
とても一般的でとても単純な何かを達成するためにこれがすべて行われなければならないということは私の心を吹き飛ばします。彼らは私たちに単純なtextField.maxLengthビルトインを与えることができませんでした...とにかくあなたのソリューションは素晴らしいです、ありがとう!
mylovemhz 2017年

1
うわー、私が今までSOで持っていた最高のヒント。できれば100票まで投票します!
jonathan3087 2017

2
解決策は便利ですが、上部のテキストフィールドのマップは実際には保持サイクルを生成します。
エンジェルG.オロキ2018

3
このソリューションを使用する場合の警告!このソリューションにはいくつかの問題があります。そのうちの1つは、ユーザーがtextFieldの先頭に入力すると、新しい文字を入力できるようになり、最後の文字が削除されます。また、カーソルがフィールドの最後の文字にジャンプします。もう1つの問題は、プログラムでテキストを設定すると、制限よりも大きいテキストを設定できるようになることです。変更を元に戻すと別の問題が発生し(外部キーボードでCMD + Z)、以前に制限を超えて数字を追加しようとするとクラッシュします。
juancazalla

25

Swift 4は、単に以下を使用します。

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

これが選択された答えになるはずです。シンプルでうまく機能します。
user832 2018

9
動作しません。文字列の途中をタップして、X文字以上を入力できるとどうなりますか。
Slavcho 2018

range.location <10の代わりに、textField.text.length <10を使用できます。このソリューションはシンプルでエレガントです。
SaqibSaud19年

あなたは、このソリューションを使用することができます。textField.text .count> = 12 {リターン偽}もし?
СергейБилык

1
過去のアクションで作業したい場合は、テキストを過ぎても機能しませんstring.count < MAX_LENGTH
RezaDehnavi20年

12

Steven Schmatzが行ったのと同じ方法ですが、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
}

1
いい答えです。感謝。
Hasya

あなた@Hasyaありがとう
Pavlos

9

Swift 5の場合:
1行を書き込むだけで、最大文字長を設定できます。

 self.textField.maxLength = 10

詳細については、ここをクリックしてください

クレジット:http//www.swiftdevcenter.com/max-character-limit-of-uitextfield-and-allowed-characters-swift/


このソリューションは簡単に思えるかもしれませんが、実際には、これを実装するために必要なコードはもっとたくさんあります。この回答自体はあまり役に立ちません。説明を追加したり、他の関連するコードを含めたりすると役立つ場合があります。
のfontFamily

6

これには拡張機能の方が便利だと思います。ここで完全な答えを参照してください

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

上記に投稿された他のソリューションは、テキストフィールドマップのために保持サイクルを生成します。さらに、maxLengthプロパティは、人工的なものではなく、設定されていない場合はnull可能である必要がありますInt.max構造のます。maxLengthが変更されると、ターゲットは複数回設定されます。

ここでは、メモリリークやその他の修正を防ぐための弱いマップを使用したSwift4の更新されたソリューションを示します

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

回答ありがとうございます。maxLengthsについて説明していただけますか?
Keyhan Kamangar 2018

4

デリゲートを使用しない簡単なソリューション:

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
私が探している答え:D
Ankur Lahiry 2018年

1
これは、定型コードのない、シンプルでエレガントなソリューションです。
zeeshan

3

My Swift4バージョンの 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
    }

これは受け入れられた答えでなければなりません。バグなしで完璧に動作します。
106231 6919年

2

アラジンの答えに追加するものがあります:

  1. ビューコントローラは以下に準拠する必要があります UITextFieldDelegate

    class MyViewController: UIViewController, UITextViewDelegate {
    
    }
    
  2. テキストフィールドのデリゲートを設定する:デリゲートを設定するには、テキストフィールドからストーリーボードのビューコントローラへのドラッグを制御できます。これはコードで設定するよりも好ましいと思います

  3. ビューコントローラにメソッドを実装します。 textField(_:shouldChangeCharactersInRange:replacementString:)


2

@Frouoに基づいて補足的な回答をします。彼の答えが最も美しい方法だと思います。それは私たちが再利用できる一般的なコントロールだからです。そして、ここではリークの問題はありません。

    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

文字列の文字数を確認するだけです

  1. デリゲートを追加して、コントローラーを表示し、デリゲートに署名します
    class YorsClassName : UITextFieldDelegate {

    }
  1. テキストフィールドに許可されている文字数を確認してください
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    if textField.text?.count == 1 {
        return false
    }
    return true
}

注:ここでは、textFieldで許可されている文字のみをチェックしました


2

このふとっちょの答えの更新

ありがとう

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での作業

//ステップ1はUITextFieldDelegateを設定します

    class SignUPViewController: UIViewController , UITextFieldDelegate {

       @IBOutlet weak var userMobileNoTextFiled: UITextField!

        override func viewDidLoad() {
            super.viewDidLoad()

//ステップ2委任を設定
userMobileNoTextFiled.delegate = self //委任を設定}

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

//ステップ3は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
        }
    }

1

この答えはSwift4に対するものであり、バックスペースを通過させる機能を備えているため、非常に簡単です。

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

これは、コピーを処理して貼り付けていません
cornr

1

Swift4でテキストをブロックした後のTextField制限文字

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

念のため、文字列に適用する前に範囲サイズを保護することを忘れないでください。そうしないと、ユーザーがこれを行うとクラッシュします。

最大長のテキストを入力します何かを挿入します(長さの制限のため何も挿入されませんが、iOSはそれを認識しません)挿入を元に戻します(クラッシュし、範囲が実際の文字列サイズより大きくなります)

また、iOS 13ユーザーを使用すると、ジェスチャーによって誤ってこれをトリガーする可能性があります

これをプロジェクトに追加することをお勧めします

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

そして、次のように使用します。

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
}

そうしないと、アプリで常にクラッシュすることになります


0

これは、不要な文字列操作を回避するSwift3.2以降の代替手段です。この場合、最大長は10です。

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

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

0

私はこのステップを使用します。最初にviewdidloadにデリゲートtexfieldを設定します。

    override func viewDidLoad() {
        super.viewDidLoad()

        textfield.delegate = self

    }

UITextFieldDelegateをインクルードした後、shouldChangeCharactersInを実行します。

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

1ページにさまざまな長さのチェックがある複数のtextFieldがある場合、簡単で短い解決策を見つけました。

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)
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.