
채팅 UI를 만들면서 채팅창을 터치하면 키보드가 내려가도록 하고 싶었지만, 전송 버튼을 터치했을 때는 키보드가 내려가지 않도록 하고 싶었습니다.
그런데 채팅창을 터치할 때 UICollectionView의 이벤트가 발생하여, 특정 뷰(UIControl)의 터치 이벤트는 gestureRecognizer가 감지하지 않도록 처리하려고 했습니다.
import UIKit
extension UIViewController {
func hideKeyBoardWhenTappedScreen() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapHandler))
tapGesture.cancelsTouchesInView = false
tapGesture.delegate = self
view.addGestureRecognizer(tapGesture)
}
@objc func tapHandler() {
view.endEditing(true)
}
}
extension UIViewController: @retroactive UIGestureRecognizerDelegate {
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
// 버튼이나 특정 뷰에 대한 터치가 gestureRecognizer에 전달되지 않도록 설정
if let view = touch.view, view is UIControl {
return false
}
return true
}
}
@retroactive는 타입이 정의된 모듈과 관계없이 프로토콜을 적용할 수 있도록 허용하는 속성입니다.
위의 코드에서 UIViewController는 UIKit 프레임워크에서 정의된 타입이며, 원래 UIGestureRecognizerDelegate 프로토콜을 직접 채택하지 않았습니다.
하지만 @retroactive를 사용하면, UIKit이 선언된 모듈과 상관없이 UIViewController가 UIGestureRecognizerDelegate 프로토콜을 구현할 수 있습니다.
따라서 외부 라이브러리에서 정의된 타입에도 새로운 프로토콜을 적용할 수 있는 유연성이 생깁니다.