본문 바로가기

Swift

UITextField에 글자 수 제한 걸기 (Max Length, Limit Length)

글자 수 제한을 걸어야 하는 경우가 생긴다.

나의 경우 collectionView에 두 개의 TextField가 있고 첫 번째 것은 이름, 두 번째 것은 나이를 입력받는다.


stackoverflow에서 힌트를 얻어 다음과 같이 코드를 작성하였는데 한글/영어 모두 잘 작동된다.

한 번에 여러 글자를 복사해서 붙여 넣는 경우 마지막 글자를 지우는게 아니어서 약간의 버그가 있긴 하지만 큰 문제가 될 것 같진 않다.


func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    guard let text = textField.text else { return true }

    let newLength = text.characters.count + string.characters.count - range.length
    debugPrint("newLength = \(newLength)")
    if newLength > 10 {
        // label에 경고 문구를 띄운다.
        let cell = self.collectionView.cellForItemAtIndexPath(NSIndexPath(forRow: 1, inSection: currentSection!)) as! SettingsCell
        cell.cellLabel.text = "\((cell.cellLabel.text)!)\n(이름은 10글자를 넘으면 안되요~)"
        for _ in 0 ..< newLength - 10 {
            textField.deleteBackward()
        }

    }
    return true
}


처음에 이렇게 작성하였으나 더 좋은 소스를 발견하여 아래와 같이 수정하였다. 물론 위의 버그도 해결하였다.


func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

    let currentText = textField.text ?? ""
    let prospectiveText = (currentText as NSString).stringByReplacingCharactersInRange(range, withString: string)

    switch currentSection! {
    case 0:
        // name
        let length = prospectiveText.characters.count
        if length > 10 {
            // label에 경고 문구를 띄운다.
            let cell = self.collectionView.cellForItemAtIndexPath(NSIndexPath(forRow: 1, inSection: currentSection!)) as! SettingsCell
            cell.cellLabel.text = "\((cell.cellLabel.text)!)\n(이름은 10글자를 넘으면 안되요~)"

        }
        return prospectiveText.characters.count <= 10
    case 1:
        // age
        if !prospectiveText.containsOnlyCharactersIn("0123456789") {
            // label에 경고 문구를 띄운다.
            let cell = self.collectionView.cellForItemAtIndexPath(NSIndexPath(forRow: 1, inSection: currentSection!)) as! SettingsCell
            cell.cellLabel.text = "\((cell.cellLabel.text)!)\n(나이는 숫자만 적어주세요~)"

        }
        return prospectiveText.containsOnlyCharactersIn("0123456789") && prospectiveText.characters.count <= 3
    default:
        return true
    }
}


이 소스에는 String extension을 사용하는데 extension source는 아래 링크에서 확인할 수 있다.

물론 이 source가 위 코드의 원천이다.


http://www.globalnerdy.com/2015/04/27/how-to-program-an-ios-text-field-that-takes-only-numeric-input-or-specific-characters-with-a-maximum-length/





한편, 다른 기능도 구현해보고 싶다.

예컨대 사용자가 키입력 때마다 실시간 조회를 해 보거나 할 때 사용해보려 한다.

오토마타라고 하는 것 같은데..

한글 입력 판단이 생각보다 간단하지가 않다. 어딘가 오픈소스로 나와있을 것 같은데..


func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    debugPrint("\(textField.text)   \(string) \(range)")
    return true
}


이렇게 키 입력을 찍어 보면 아래와 같이 나온다.

"Optional(\"\")   T (0,0)"

"Optional(\"T\")   y (1,0)"

"Optional(\"Ty\")   Typical (0,2)"

"Optional(\"Typical\")     (7,0)"

"Optional(\"Typical \")   (8,0)"

"Optional(\"Typical \")   (9,0)"

"Optional(\"Typical \")   (9,0)"

"Optional(\"Typical \")   (9,0)"

"Optional(\"Typical 예소\")   (10,0)"

"Optional(\"Typical 예송\")   f (8,0)"

"Optional(\"Typical f예송\")   u (9,0)"

아래는 결과 화면..