iOS 응용 (swift)

[iOS - swift] UITextField 포맷 (핸드폰 번호, 이메일, 카드 번호) - AnyFormatKit 사용

jake-kim 2020. 12. 9. 23:36

cocoapod

pod 'AnyFormatKit'

구현

  • import
import AnyFormatKit
  • 델리게이트 함수에 적용
    textField
    (_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool

예제1) 폰 번호 포맷 - 010-1234-2134

extension ViewController: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        guard let text = textField.text else {
            return false
        }
        let characterSet = CharacterSet(charactersIn: string)
        if CharacterSet.decimalDigits.isSuperset(of: characterSet) == false {
            return false
        }

        let formatter = DefaultTextInputFormatter(textPattern: "###-####-####")
        let result = formatter.formatInput(currentText: text, range: range, replacementString: string)
        textField.text = result.formattedText
        let position = textField.position(from: textField.beginningOfDocument, offset: result.caretBeginOffset)!
        textField.selectedTextRange = textField.textRange(from: position, to: position)
        return false
    }
}

* 주의사항

  • return false하게 되면, rx를 쓸 경우 textField.rx.text이벤트가 발생하지 않음
  • return false를 하게 되어도, 위 델리게이트 함수에서 textField.text에 값을 입력하면 반영 됨
  • textField.selectedTextRange를 통해 cursor의 위치를 바꾸어 줌

예제2) 카드 비밀번호 2자리 포맷 - 34**

xtension ViewController: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        guard var text = textField.text else {
            return false
        }
        let characterSet = CharacterSet(charactersIn: string)
        if CharacterSet.decimalDigits.isSuperset(of: characterSet) == false {
            return false
        }

        let newLength = text.count + string.count - range.length

        if (range.length == 2 || range.length == 4) && string.isEmpty { // 2개 이상 선택하여 삭제하는 경우
            textField.text = ""
            return false
        }

        let formatter = DefaultTextInputFormatter(textPattern: "##**", patternSymbol: "#")
        if newLength == 2 {
            text += " "
        }
        let result = formatter.formatInput(currentText: text, range: range, replacementString: string)
        textField.text = result.formattedText
        let position = textField.position(from: textField.beginningOfDocument, offset: result.caretBeginOffset)!
        textField.selectedTextRange = textField.textRange(from: position, to: position)
        return false

    }
}

활용) 핸드폰 번호 포멧 및 커서 위치 자동 설정 extension (10 ~ 11자리 핸드폰 번호)

extension UITextField {
    func formatPhoneNumber(range: NSRange, string: String) {
        guard let text = self.text else {
            return
        }
        let characterSet = CharacterSet(charactersIn: string)
        if CharacterSet.decimalDigits.isSuperset(of: characterSet) == false {
            return
        }

        let newLength = text.count + string.count - range.length
        let formatter: DefaultTextInputFormatter
        let onlyPhoneNumber = text.filter { $0.isNumber }

        let currentText: String
        if newLength < 13 {
            if text.count == 13, string.isEmpty { // crash 방지
                formatter = DefaultTextInputFormatter(textPattern: "###-####-####")
            } else {
                formatter = DefaultTextInputFormatter(textPattern: "###-###-####")
            }
        } else {
            formatter = DefaultTextInputFormatter(textPattern: "###-####-####")
        }

        currentText = formatter.format(onlyPhoneNumber) ?? ""
        let result = formatter.formatInput(currentText: currentText, range: range, replacementString: string)
        if text.count == 13, string.isEmpty {
            self.text = DefaultTextInputFormatter(textPattern: "###-###-####").format(result.formattedText.filter { $0.isNumber })
        } else {
            self.text = result.formattedText
        }

        let position: UITextPosition
        if self.text?.substring(from: result.caretBeginOffset - 1, to: result.caretBeginOffset - 1) == "-" {
            position = self.position(from: self.beginningOfDocument, offset: result.caretBeginOffset + 1)!
        } else {
            position = self.position(from: self.beginningOfDocument, offset: result.caretBeginOffset)!
        }

        self.selectedTextRange = self.textRange(from: position, to: position)
    }
}

- 사용하는 입장:

extension MyVC: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        textField.formatPhoneNumber(range: range, string: string)
        return false
    }
}

source code:github.com/JK0369/sampleFormat