Responder란 이벤트를 받아서 처리하는 역할을 하는 객체를 의미합니다. UIKit에서는 UIResponder라는 객체로 구현이 되어 있는데 이를 상속받는 하위 객체는 UIView, UIViewController, UIApplication 등이 있습니다. 따라서 UIKit의 객체들은 이벤트를 받아서 스스로 처리하거나 다른 객체가 처리할 수 있도록 넘기는 역할을 할 수 있습니다.
First Responder는 이벤트가 발생했을 때 iOS가 최초로 이벤트를 넘겨주는 Responder를 의미합니다.
그렇다면 resignFirstResponder의 역할은 쉽게 이해할 수 있습니다. 특정 객체가 First Responder로서의 역할을 사퇴(?)한다는 의미입니다. 즉 이 메소드를 실행하게 되면 해당 객체는 더 이상 First Responder로서의 역할을 하지 않습니다.
해당 메소드를 많이 사용하는 곳의 예시를 들면 UITextField 객체를 들 수 있습니다. UITextField 객체가 First Responder가 되면 iOS는 자동적으로 키보드를 띄웁니다. 이 키보드를 dismiss 시키기 위해서 UITextField의 resignFirstResponder 메소드를 실행하면 됩니다.
SwiftUI의 객체들에는 resignFirstResponder가 구현되어 있지 않습니다. 따라서 우회하는 방법을 사용해야 합니다.
extension UIApplication {
func dismissKeyboard() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
먼저 UIApplication 객체에 아래와 같은 함수를 추가합시다. UIApplication에 정의되어 있는 sendAction이라는 함수를 실행하는 함수입니다. 해당 함수의 설명을 보면 다음과 같이 적혀있습니다.
먼저 action으로 selector를 전달합니다. selector는 우리가 실행하고자하는 UIResponder.resignFirstResponder를 Selector 객체로 만들어서 전달합시다.
⭐️ 중요한 부분은 target입니다. (sender와 event는 잠시 접어둡시다.) target인자를 설명하는 부분을 보면 nil일 경우 해당 message는 first responder에게 보낸다고 되어 있습니다.
😀 따라서 nil을 전달하면 우리가 원하는 동작을 실행할 수 있습니다. 우리가 원하는 동작은 TextField가 First Responder가 되어서 화면에 존재하는 키보드를 TextField가 First Responder에서 resign 시켜서 키보드를 dismiss하는 것입니다.
따라서 위 함수를 실행하면 TextField resignFirstResponder를 실행하게 되고 결과적으로 키보드를 Dismiss할 수 있습니다.
TextField와 위에 만든 메소드를 실행하는 버튼을 하나 만들어둡시다. TextField를 클릭하면 키보드가 올라오고 버튼을 누르면 키보드가 내려갈 것입니다.
struct ResignFirstResponder: View {
@State private var text: String = ""
var body: some View {
VStack {
TextField("", text: $text)
.frame(width: 120, height: 20)
.padding(5)
.border(.black, width: 1)
.multilineTextAlignment(.trailing)
Button(action: {
UIApplication.shared.dismissKeyboard()
}, label: {
Text("Dismiss Keyboard")
})
}
}
}
의도한 대로 실행되는 것을 볼 수 있습니다.