ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [iOS/Swift] RxGesture - Gesture가 동시에 인식되는 문제
    야매 iOS 2023. 8. 7. 20:14

    문제

    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가 다르므로 이 메서드뿐만 아니라 다른 메서드를 사용할 때도 주의해서 사용해야 함

    '야매 iOS' 카테고리의 다른 글

    [iOS/Swift] RxSwift subscribe flow  (0) 2023.08.07
    [Swift] Dispatch  (0) 2023.08.07
    [Swift] Copy on Write  (0) 2023.08.07
    [iOS/Swift] SwiftUI 계산기  (0) 2023.08.07
    [iOS] Certificate & Provisioning  (0) 2023.08.07
Designed by Tistory.