안녕하세요, 오늘은 Swift에서 UITextView의 글자수를 제한하는 방법에 대해 알아보겠습니다. 사실 이러한 방법에 대해서는 이미 많은 블로그에 소개되어 있습니다.
그런데 한글의 글자수를 제한할 때 에러 사항이 많아서 저만의 방법으로 한글 수를 제한하는 법을 소개드리려고 이렇게 글을 작성하게 되었습니다.
아래의 코드는 UITextView의 글자수를 제한할 때 보통 사용되는 코드입니다
extension CustomTableViewCell: UITextViewDelegate {
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// 텍스트 뷰의 현재 텍스트와 새로 입력되는 텍스트를 결합합니다.
let currentText = textView.text ?? ""
let prospectiveText = (currentText as NSString).replacingCharacters(in: range, with: text)
print("현재 문자열: \(currentText), 합쳐진 문자열: \(prospectiveText), 문자열 길이: \(prospectiveText.count), 입력되어진 문자열: \(text)")
// 새로운 텍스트의 길이가 제한보다 작거나 같으면 텍스트 변경을 허용합니다.
return prospectiveText.count <= characterLimit
}
}
`textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool`: 텍스트 뷰의 텍스트가 변경될 때마다 호출됩니다. 이 메서드 입력되어진 텍스트로 바꿀지 여부를 대리자에게 묻습니다.
이렇게 작성하면 영어 입력 시에는 정상적으로 작동합니다. 그런데 문제는 한글의 경우, `shouldChangeTextIn` 메서드에서 `replacingCharacters`를 사용하면 자음과 모음이 분리되는 문제가 발생합니다. 예를 들면 화면상에 '아'까지 입력 후에 'ㄴ'을 입력하면 기대하는 결과는 '안'이 나와야 하지만, 'replacingCharacters' 메서드는 '아ㄴ'이라는 값을 내보내고 있습니다. 그로 인해 'prospectiveText.count'도 기대했던 1이 아닌 2가 나와 원치 않는 위치에서 제한이 걸리게 됩니다.
그래서 그 이후로 생각한 것이 한글의 경우 입력 전에 글자수를 제한하는 것이 아닌, 입력 후에 완성된 글에서 확인하면 되지 않을까 생각해 다른 방법으로 접근해본 것이 아래의 'textViewDidChange(_ textView: UITextView)' 메서드입니다:
extension CustomTableViewCell: UITextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
// 텍스트 뷰의 현재 텍스트를 가져옵니다.
let currentText = textView.text ?? ""
// 현재 텍스트의 길이를 계산합니다.
var length = currentText.count
// 길이가 제한을 초과하면 텍스트 변경을 취소합니다.(characterLimit = 50)
if length > characterLimit {
// 텍스트를 제한 길이만큼 잘라냅니다.
textView.text = String(currentText.prefix(characterLimit))
}
}
}
'textViewDidChange(_ textView: UITextView)': 텍스트가 변경된 후에 호출됩니다. 이 메서드에서는 변경된 텍스트를 확인하고 변경할 수 있습니다.
위의 코드대로 하면 한글로 입력 시에 원하는 위치에서 제한이 걸리는 것을 확인할 수 있었습니다. 그런데 또 다른 문제가 발생했습니다. 제한되는 위치에서 한글을 계속 입력하면 마지막 글자만 입력한 글자로 바뀌는데, 문제는 백스페이스로 맨 뒤에서 지울 시에 전에 입력되었던 마지막 글자들이 나타나는 현상을 발견했습니다. (정확한 원인은 모르겠습니다.)
그래서 textViewDidChange에서 textView를 다 비워서 다시 넣기도 해보고 여러 가지 시도를 해봤지만, 텍스트가 완성된 후에는 안된다는 것을 깨달은 후 입력되기 전에 체크하는 'textView(shouldchangeTextIn)'에서 해결했습니다. 해당 결과물이 아래와 같습니다.
구현 코드
extension CustomTableViewCell: UITextViewDelegate {
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let currentText = textView.text ?? ""
// text.count == 0 : text.count 가 0 인경우는 공백, 즉, 백스페이스가 입력된 경우입니다 코드내에서 직접적으로 text = "" 작성하지않는 이상 현재까지는 백스페이스 입력값 이외에는 0인 값을 발견하지 못함
// range.location + 1 >= characterLimit : 백스페이스 입력 위치 조건값 (제한길이에 도달한 위치에서 백스페이스 입력시)
if text.count == 0 && currentText.count >= characterLimit && range.location + 1 >= characterLimit {
textView.text.removeLast()
return false
}
return true
}
func textViewDidChange(_ textView: UITextView) {
// 텍스트 뷰의 현재 텍스트를 가져옵니다.
let currentText = textView.text ?? ""
// 현재 텍스트의 길이를 계산합니다.
var length = currentText.count
// 길이가 제한을 초과하면 텍스트 변경을 취소합니다.
if length > characterLimit {
// 텍스트를 제한 길이만큼 잘라냅니다.
textView.text = String(currentText.prefix(characterLimit))
}
}
}
문제의 해결책은 비교적 간단했습니다. 'textViewDidChange'는 이전에 작성한 대로 유지하되, 문제가 발생했던 마지막 위치에서 백스페이스 입력 시에 대한 처리를 'textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool' 함수에서 직접 수행하도록 설정했습니다. 즉, 마지막 위치에서 백스페이스가 입력될 때 코드로 직접 마지막 문자를 삭제하도록 했습니다. 이 변경으로 문제가 해결되었습니다. 현재까지는 추가적인 문제점을 발견하지 못했지만, 더 효율적인 해결 방법을 알고 계시다면 언제든지 댓글로 공유해 주시기 바랍니다.
'Swift' 카테고리의 다른 글
[Swift] iOS에서 Google AdMob을 통한 보상형 광고 적용하기 (0) | 2023.06.13 |
---|---|
[Swift] iOS에서 Google AdMob 사용하는 방법 (0) | 2023.06.13 |
[Swift] 카카오 API를 이용한 중부원점(EPSG:2097) 좌표를 위도·경도(WGS84)로 변환하는 방법 (0) | 2023.03.08 |
[Swift]SQLite3사용 예제 (feat.FMDB) (0) | 2023.02.10 |
[Swift] 네이버 오픈 API 지역 검색 (0) | 2023.02.10 |