적당한 고통은 희열이다

- 댄 브라운 '다빈치 코드' 중에서

Project/ToyProject_Shopping List

[Swift iOS] 흥미로운 UITextFieldDelegate

hongssup_ 2021. 3. 27. 21:12
반응형

UITextField는 재미있는 친구다. 

이 친구를 더욱 다양한 방법으로 활용하기 위해서는 UITextFieldDelegate 프로토콜을 추가해주어야 한다. 

그런다음 textField.delegate = self 로 상속받기. 

 

굉장히 간단한 쇼핑 리스트 앱을 만들어보고자 했지만, 생각보다 UITextField를 다루기가 쉽지 않았다.

보통은 새로운 창을 띄워 텍스트를 입력하고 저장하면 목록에서 볼 수 있도록 하는 방법으로 text field를 많이 사용하지만, 

새로운 창 같은거 띄우지 않고 그냥 테이블뷰 목록에서 직접 입력하고 편집하고 값 저장하고 다 하려니까 UITextFieldDelegate에 대해 아주 깊게 탐구해보게 되었다. 

 

애플 개발자 문서를 찾아보면

<UITextFieldDelegate> 란?

키보드 입력 및 전반적인 text field 편집과 관련된 기능들을 수행하는 프로토콜이라고 한다. 

텍스트필드 편집 과정의 흐름을 살펴보면,

1. textFieldShouldBeginEditing(_:) 

2. text field가 활성화 되면 텍스트 입력을 위한 키보드 생성

(보통 해당 text field를 터치하면 바로 활성화가 되지만, 터치 하기 전에 자동으로 text field 입력을 시작하도록 키보드를 띄우고 싶다면 textField.becomeFirstResponder() 를 선언해주면 된다.)

3. textFieldDidBeginEditing(_:)

4. text field 편집 중에 호출되는 다양한 delegate 메서드들

그 중, textFieldShouldReturn(_:)은 사용자가 키보드의 return 버튼을 탭 했을 때 호출되는 함수로 꽤 유용하게 쓰인다.

5. textFieldShouldEndEditing(_:) 

6. text field 비활성화 하고 키보드 숨기기 (textField.resignFirstResponder() 로 직접 호출 가능)

7. textFieldDidEndEditing(_:) 

 

내가 사용한 기능들

 

** start editing UITextField and show keyboard

먼저 항목 추가 버튼을 눌러 새로운 테이블뷰 셀이 생성되면, 자동으로 text field가 활성화되고 키보드가 올라오게 하기 위해서

tableView의 cellForRowAt indexPath 함수에 다음을 추가해주었다. 

textField.becomeFirstResponder()

** keyboard dismiss with return Button

키보드의 입력 완료 버튼을 눌렀을때 키보드가 사라지게 하고 싶다면 UITextFieldDelegate 프로토콜을 상속받은 클래스 안에

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}

** keyboard dismiss by touching anywhere in the view

화면 아무데나 터치 해도 키보드가 사라지게 하고 싶다면 

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?){
    super.touchesBegan(touches, with: event) //
    self.view.endEditing(true)
}

이방법을 쓰면 된다고 많이 나와 있던데 나는 안되더라. 읭?.?

그래서 다음 코드를 viewDidLoad에 추가해주었더니 잘 되더라. 화면 아무데나 터치하면 endEditing이 호출되도록 해서 키보드를 없애주었다. 

let tapGesture = UITapGestureRecognizer(target: view, action: #selector(view.endEditing))
view.addGestureRecognizer(tapGesture)

** save UITextField text into UITableView cell

텍스트를 완료한 후 입력 버튼을 누르거나 화면 아무데나 터치하면, 입력된 텍스트를 해당 cell 저장하기 위해 다음과 같이 작성해주었다. 

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}

func textFieldDidEndEditing(_ textField: UITextField) {
    let textFieldIndexPath = self.tag
    endTextEdit(textField.text ?? "", textFieldIndexPath)
}

func endTextEdit(_ text: String, _ tag: Int) {
    items[tag] = text
    tableView.reloadData()
}

위의 두 함수는 UITextFieldDelegate 프로토콜에서 상속받은 내장 함수로,

첫 번째 함수에서는 사용자가 키보드의 return 버튼을 눌렀을 때 .resignFirstResponder() 메서드를 호출하여 키보드가 사라지도록 했다.

두 번째 textFieldDidEndEditing() 함수는 .resignFirstResponder() 가 호출되었을 때 호출되는 함수로, 화면을 탭하여 text field가 비활성화 되거나, 키보드의 return을 눌러 입력을 비활성화 했을 때 작동한다. 그래서 나는 이 함수로부터 해당 UITextField의 tag 값과 text를 받아와서, 마지막 endTextEdit 함수에 값을 넘겨주고 reloadData() 를 해주었다. 

 

+ 키보드 입력에 실시간으로 반응하고 싶다면?

@objc func textFieldDidChange(_ textField: UITextField) {
    // 키보드 업데이트 시 원하는 기능 
}

키보드 업데이트시 작동시킬 @objc 함수를 만들어주고, textField에 .editingChanged 라는 UIControl Event로 함수를 작동시키면 키보드 입력을 실시간으로 반영할 수 있다. 

textField.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)

 

 

 

Q. UITapGestureRecognizer를 사용하여 입력을 비활성화한 후 입력받은 텍스트를 저장할 경우 생기는 문제점?

작동 자체에는 문제가 없다. 그런데 화면 탭 시 textFieldDidEndEditing을 불러올경우, 화면에서 항목 추가 버튼을 좀만 길게 눌러도 함수가 여러번 계속 호출이 되더라. 작동에는 문제가 없이 잘 돌아가지만, 배열의 값이 계속 바뀌고 reloadData() 가 여러번 된다면 불필요하게 에너지를 낭비하게 되는 것 같다. 이를 어떻게 방지하나...

 

 

728x90
반응형