Swift에서 UITextField의 최대 문자 길이 설정


85

나는 이것에 다른 주제가 있다는 것을 알고 있지만 그것을 구현하는 방법을 찾을 수없는 것 같습니다.

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라는 사용자 정의로 교체해야하는 "텍스트 필드"를 모르겠습니다.



빠른 경고- 요즘 Swift에서 a 를 줄이려String마침내 .prefix (n)
Fattie

답변:


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

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
}

지정된 텍스트 필드에 지정된 문자 집합 만 입력하도록 허용

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 텍스트 필드를 프로그래밍하는 방법


신속한 답변에 감사드립니다! 이 하나의 텍스트 필드를 대리인으로 설정하면 다른 텍스트 필드를 수정할 수 있습니까?
ishkur88 2015

예, 당신은 첫 번째 매개 변수로 문제의 텍스트 필드를 (편집 중) 얻을 것이다 textField방법에있어서 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
알라딘

하지만 두 번째 매개 변수는 어디에 넣을까요? myTextField를 델리게이트로 설정 한 후에는 다시 참조하지 않습니다.
ishkur88 jul.

전화 번호로만 다른 텍스트 필드 0-9를 만들고 싶을 때처럼.
ishkur88 jul.

텍스트 필드가 편집 될 때마다 콜백 shouldChangeCharactersInRange이 호출됩니다. 이것은 모든 텍스트 필드에 대한 것입니다. 동일한 위치에서 콜백을 수신 shouldChangeCharactersInRange하고이 메서드 내에서 전달 된 매개 변수 덕분에 편집중인 텍스트 필드를 알 textField수 있습니다. 예를 들어 내부 각 텍스트 필드 테스트에 대한 태그 shouldChangeCharactersInRange및 각 텍스트 필드에 대한 콘텐츠의 유효성 검사를 수행
알라딘

113

2017 년 12 월. Swift 4.

주의해야 이 문제에 대해 온라인으로 볼 수있는 예제 코드의 대부분은 아주 오래된입니다 .

프로젝트의 Swift 파일에 다음을 붙여 넣으십시오. 파일 이름은 무엇이든 가능합니다 (예 : "Handy.swift").

이것은 마침내 iOS에서 가장 어리석은 문제 중 하나를 수정합니다.

여기에 이미지 설명 입력

이제 텍스트 필드에 .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)


더 간단한 일회성 버전 ...

위는 프로젝트의 모든 텍스트 필드를 수정 합니다 .

특정 텍스트 필드 하나 를 "4"로만 제한 하고 싶은 경우 그게 ...

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

휴! 그게 전부입니다.

(단지 BTW, UIText View 와 관련된 매우 유용한 팁 , 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. 미상

2
textView에 이와 같은 것이 있습니까?
도리

13
이 모든 것이 너무나 흔하고 단순한 일을 성취하기 위해 이루어져야한다는 사실이 제 마음을 사로 잡습니다. 그들은 우리에게 간단한 textField.maxLength 내장을 제공 할 수 없었습니다. 어쨌든 귀하의 솔루션은 훌륭합니다. 감사합니다!
mylovemhz

2
솔루션은 편리하지만 상단의 텍스트 필드 맵은 실제로 유지주기를 생성합니다.
Angel G. Olloqui

3
이 솔루션을 사용하는 사람들을위한 경고! 이 솔루션에는 몇 가지 문제가 있습니다. 그중 하나는 사용자가 textField 시작 부분에 입력하면 새 문자를 입력하도록 허용하고 마지막 문자가 제거되고 커서가 필드의 마지막 문자로 이동한다는 것입니다. 또 다른 문제는 텍스트를 프로그래밍 방식으로 설정하면 제한보다 큰 텍스트를 설정할 수 있다는 것입니다. 변경 사항 (외부 키보드의 CMD + Z)을 실행 취소하면 이전에 한도를 초과하는 숫자를 추가하려고하면 충돌이 발생하는 또 다른 문제가 발생합니다.
juancazalla

26

Swift 4, 간단히 사용 :

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

이것은 선택된 대답이어야합니다. 간단하고 잘 작동합니다.
user832 dec

9
작동하지 않습니다. 문자열 중간을 탭하고 X 자 이상을 입력 할 수 있다면 어떨까요?
Slavcho

range.location <10 대신 textField.text.length <10을 사용할 수 있습니다.이 솔루션은 간단하고 우아합니다.
Saqib Saud

이 솔루션을 사용할 수 있습니다. if textField.text? .count> = 12 {return false}
Сергей Билык

1
당신이 작업 할 경우 텍스트지나 때 작동하지 않는 과거의 당신은 추가해야합니다 액션string.count < MAX_LENGTH
레자 Dehnavi

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


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인위적인 Int.max구조 대신 설정하지 않으면 속성은 nullable이어야합니다 . 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

3

델리게이트를 사용하지 않는 간단한 솔루션 :

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

1
이것은 상용구 코드가없는 간단하고 우아한 솔루션입니다.
zeeshan

3

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

이것은 받아 들여진 대답이어야합니다. 버그없이 완벽하게 작동합니다.
10623169

2

Aladin의 답변에 추가 할 것이 있습니다.

  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

이것에 대한 업데이트 Fattie 답변에 대한

감사

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

     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

이 답변은 Swift 4에 대한 것이며 백 스페이스를 통과시키는 기능으로 매우 간단합니다.

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

이것은 복사 및 붙여 넣기를 처리하지 않습니다.
cornr

1

문자열의 문자 수만 확인하면됩니다.

  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에서 허용되는 문자 만 확인했습니다.


1

Swift 4에서 텍스트 차단 후 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

불필요한 문자열 조작을 피하는 Swift 3.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

한 페이지에 다양한 길이 검사가있는 여러 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.