[iOS/Swift] RxGesture - Gesture가 동시에 인식되는 문제
문제
environment
UIScrollView가 있고 subview로 UITextField를 가짐
UIScrollView에 rx.tapGesture를 사용해 TapGesture 적용
- UIScrollView를 탭했을 때 키보드를 내리기 위해
problem
UITextField를 터치했을 때 interaction이 어색함
해결
TL;DR
scrollView.rx.tapGesture() // 수정 전
scrollView.rx.tapGesture(configuration: { _, config in // 수정 후
config.simultaneousRecognitionPolicy = .never
})
config.simultaneoulsyRecognitionPolicy 프로퍼티에 .never를 넣어주면 됨
RxGesture
RxGesture는 configuration을 설정할 수 있는 구조로 되어 있음
extension Reactive where Base: RxGestureView {
public func tapGesture(configuration: TapConfiguration? = nil) -> TapControlEvent {
gesture(make(configuration: configuration))
}
}
Configuration
RxGesture에서 Configuration은 클로저로 구성되어 있다.
- GestureRecognizer와 Delegate를 인자로 받는 클로저
typealias Configuration<Gesture: RxGestureRecognizer> = (Gesture, GenericRxGestureRecognizerDelegate<Gesture>) -> Void
사용할 때 GestureRecognizer 또는 Delegate에 접근해서 값을 커스텀할 수 있다.
GenericRxGestureRecognizerDelegate
UIGestureRecognizerDelegate에 대응되는 값들을 갖고 있다
struct GestureRecognizerDelegatePolicy {
private init policy: @escaping PolicyBody) {
self.policy = policy
}
public static var always: GestureRecognizerDelegatePolicy<PolicyInput> {
.init { _ in true }
}
public static var never: GestureRecognizerDelegatePolicy<PolicyInput> {
.init { _ in false }
}
func isPolicyPassing(with args: PolicyInput) -> Bool {
policy(args)
}
}
final class GenericRxGestureRecognizerDelegate<Gesture: RxGestureRecognizer> RxGestureRecognizerDelegate {
...
simultaenousRecognitionPolicy: GestureRecognizerDelegatePolicy<(Gesture, RxGestureRecognizer)> = .always
public func gestureRecognizer(
_ gestureRecognizer: RxGestureRecognizer,
shouldRecognizeSimultaenouslyWith otherGestureRecognizer: RxGestureRecognizer
) -> Bool {
simultaenousRecognitionPolicy.isPolicyPassing (with: (gesture as! Gesture, otherGestureRecognizer))
}
}
해결
shouldRecognizeSimultaenouslyWith otherGestureRecognizer 의 default value가 .always 였으므로 이벤트를 UITextField도 받고 UIScrollView도 받아서 생기는 문제였음
→ 프로퍼티의 값을 .always(true)에서 .never(false)로 변경하니 UITextField의 Gesture와 UIScrollView에 적용된 TapGesture가 동시에 인식되지 않아 문제 해결
UIGestureRecognizerDelegate의 gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer)
디폴트 값은 false이지만 RxGesture에선 true로 설정되어 있음
실제 Delegate과 defaultValue가 다르므로 이 메서드뿐만 아니라 다른 메서드를 사용할 때도 주의해서 사용해야 함