본문 바로가기
Project/SwiftUI 블록와이드

[SwiftUI Project] 텍스트필드 글자 수 제한하기 (문제 해결 과정)

by iOS_woo 2022. 10. 19.

문제 해결 후의 텍스트필드
텍스트필드가 늘어나는 문제..

이번에는 텍스트 필드의 글자수를 제한하여 UI가 변경되는 것을 방지하였습니다. 

간단한 기능이라고 생각하고 미루다가 작업을 해보았는데.. 생각보다 쉽지만은 않았습니다.

 

1. View 혹은 SearchBar의 Frame(height:)에 값을 주는 방법으로는 해결되지 않았습니다. 

 

2. 구글링하여 didSet, onChange, onReceive 등의 자료들을 찾아보았지만 작동하지 않았습니다. 

didSet은 xCode13+에서 해당 문제를 해결할 수 없다는 의견이었고, onChange와 onReceive는 작동하지 않았습니다. 

ViewModel에 있는 @Published var searchText: String = ""  변수의 글자 수를 제어하려는 시도였습니다.  

 

관련 문서: 

 

SwiftUI TextField max length

Is it possible to set a maximum length for TextField? I was thinking of handling it using onEditingChanged event but it is only called when the user begins/finishes editing and not called while us...

stackoverflow.com

 

3. 아무래도 제가 사용하는 텍스트필드가  UITextField를 사용하기 때문에 작동하지 않는게 아닐까 생각하였습니다. 

검색 키워드를 바꿔 UITextField에서 글자 수를 제한하는 방법을 찾기 시작했고 마침내 해결 할 수 있었습니다. 

 

이번 프로젝트에서는 TextField가 보일 시 자동으로 선택되는 FirstResponderTextField를 사용했었는데요.

기존 코드에 글자 수 제한 코드를 추가하였습니다.

struct FirstResponderTextField: UIViewRepresentable {
    
    class Coordinator: NSObject, UITextFieldDelegate {
        
        @Binding var searchText: String
        var becameFirstResponder = false
        
        init(searchText: Binding<String>) {
            self._searchText = searchText
        }
        
        func textFieldDidChangeSelection(_ textField: UITextField) {
            searchText = textField.text ?? ""
            textField.text = String(searchText.prefix(15)) // 글자 수 제한
        }
        
        // 리턴키를 누를 시 포커스 해제
        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            textField.resignFirstResponder()
            return true
        }
    }
    
    @Binding var searchText: String
    let placeHolder: String
    
    func makeUIView(context: Context) -> some UIView {
        let textField = UITextField()
        textField.delegate = context.coordinator
        textField.placeholder = placeHolder
        return textField
    }
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(searchText: $searchText)
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        if !context.coordinator.becameFirstResponder {
            uiView.becomeFirstResponder()
            context.coordinator.becameFirstResponder = true
        }
    }
}

 

단 한줄을 추가하는 것으로 문제를 해결할 수 있었습니다.

func textFieldDidChangeSelection(_ textField: UITextField) {
            searchText = textField.text ?? ""
            textField.text = String(searchText.prefix(15)) // 글자 수 제한
        }

ViewModel로부터 바인딩되는 SearchText에 textField.text의 값이 입력되는 구조입니다. 

 

ViewModel에서 @Published var searchText: String = "" 의 String을 didSet 등등으로 제한하려고 했던 것은 실패하였는데요. 

조금 더 내려와서(?)  textField.text의 String을 제한하는 코드를 통해 문제가 해결되었습니다.

 

혹시 FirstResponderTextField를 사용하신다면 다음과 같이 사용 하실 수 있습니다. 

FirstResponderTextField(searchText: $searchText, placeHolder: "검색")

 

 

 

댓글