ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • UIGestureRecognizerRepresentable 사용하기
    SwiftUI 2024. 12. 16. 18:55

    안녕하세요. 그린입니다 🍏

    이번 포스팅에서는 SwiftUI의 UIGestureRecognizerRepresentable에 대해 학습해보겠습니다 🙋🏻

     


    UIGestureRecognizerRepresentable?

    UIGestureRecognizerRepresentable는 이번 WWDC 2024에서 소개되었는데요.

    iOS 18이상에서 사용 가능합니다.

     

    UIGestureRecognizerRepresentable는 SwiftUI에서 UIKit의 제스처 인식기를 사용할 수 있게 해주는 프로토콜이에요.

    우리 UIViewRepresentable이 SwiftUI에서 UIKit의 뷰를 사용할 수 있게 도와주는 프로토콜이었던것과 같은 맥락이죠.

    해당 프로토콜을 통해서 우리는 SwiftUI 뷰에서 UIKit의 다양한 제스처 인식기를 활용해볼 수 있어요!

     

    필수적으로 해당 UIGestureRecognizerRepresentable를 채택해 제스쳐 인식기를 만들때는 구현이 필요한 메서드들이 있습니다.

     

     

    이렇게 존재하는데요.

     

    어떤 쓰임이 있는지는 실제 코드 사용을 아래에서 보면서 같이 확인해보겠습니다 🙋🏻

     


    UIGestureRecognizerRepresentable의 사용 방법

    먼저 사용 방법을 볼까요?

     

    import SwiftUI
    
    struct MultiTapGesture: UIGestureRecognizerRepresentable {
      let action: () -> Void
      
      func makeUIGestureRecognizer(context: Context) -> some UIGestureRecognizer {
        let gesture = UITapGestureRecognizer()
        gesture.numberOfTouchesRequired = 2
        gesture.delegate = context.coordinator
        return gesture
      }
    
      func makeCoordinator(converter _: CoordinateSpaceConverter) -> Coordinator {
        Coordinator()
      }
    
      func handleUIGestureRecognizerAction(
        _ recognizer: UIGestureRecognizerType, context _: Context
      ) {
        switch recognizer.state {
        case .ended:
          action()
        default:
          break
        }
      }
    
      class Coordinator: NSObject, UIGestureRecognizerDelegate {
        @objc
        func gestureRecognizer(
          _: UIGestureRecognizer,
          shouldRecognizeSimultaneouslyWith _: UIGestureRecognizer
        ) -> Bool {
          true
        }
      }
    }

     

    가장 먼저 SwiftUI에서 사용을 위해 MultiTapGesture라는 구조체 타입으로 UIGestureRecognizerRepresentable 프로토콜을 채택합니다.

     

    이제 내부 구현된 메서드들을 살펴볼께요.

     

    makeUIGestureRecognizer

    해당 메서드는 실제 UIKit의 UITapGestureRecognizer 인스턴스를 생성하고 설정하는 메서드에요.

    두 손가락 탭을 인식할 수 있도록 설정하고 또한 딜리게이트를 설정해줍니다.

    makeUIView와 비슷한 역할을 해주죠.

     

    makeCoorinator

    해당 메서드는 이제 제스처 인식기의 딜리게이트 역할을 할 Coordinator 인스턴스를 생성합니다.

    여기서 CoordinateSpaceConverter 파라미터는 좌표계 변환에 사용되지만 여기서는 사용되지 않습니다.

     

    handleUIGestureRecognizerAction

    제스처의 상태 변화를 처리해주는 메서드입니다.

    여기서는 ended 상태일 때만 지정된 action 클로저를 실행합니다.

     

    그리고 내부에 Coordinator 클래스가 있어요.

    NSObject를 상속받고 UIGestureRecognizerDelegate 프로토콜을 채택하여 구현합니다.

    UIKit의 제스처 시스템과 상호 작용하기 위해 필요한 기본 설정들을 담아요.

    gestureRecognizer 메서드는 여러 제스처가 동시에 인식될 수 있는지를 결정하는 딜리게이트 메서드입니다.

    여기서 @objc 키워드는 아시겠지만 Objective-C 런타임과의 상호 운용성을 위해서 필요하죠.

    해당 메서드에선 true를 리턴해주기에 여러 제스처가 동시에 인식될 수 있습니다.

    즉, 한 손가락 탭과 두 손가락 탭이 동시에 인식될 수 있단 소리죠.

     

    즉, 정리해보면 제스처 인식기를 생성하고 설정한 다음 딜리게이트를 생성하죠.

    그리고 실제 제스처 동작 처리를 입혀주는것입니다.

     

    그럼 이걸 SwiftUI에서 얹어볼까요?

     

    import SwiftUI
    
    struct ContentView: View {
      @State var text: String = ""
      
      var body: some View {
        Text(text)
          .frame(width: 300, height: 300)
          .background(Color.green)
          .onTapGesture {
            text = "Just Tap"
          }
          .gesture(
            MultiTapGesture {
              text = "Multi Tap"
            }
          )
      }
    }

     

    이제 gesture 메서드에 해당 컨버팅하여 가져온 MultiTapGesture를 사용함으로 편리하게 적용할 수 있어요.

    해당 코드를 보면 한 손가락 탭을 한 경우와 두 손가락 탭을 한 경우에 텍스트를 달리 나타내주도록 하고 있습니다.

     

    그럼 돌려볼까요?

     

     

    한 손가락과 두 손가락 제스처 차이가 있죠~?

     


    UIGestureRecognizerRepresentable의 특징 및 사용 케이스

    UIGestureRecognizerRepresentable는 UIKit의 모든 제스처 인식기들인 Tap, LongPress, Swipe, Pinch 등을 SwiftUI에서 쉽게 컨버팅해 사용할 수 있도록 해줍니다.

    우리가 위에서 알아본 두 손가락 제스처에 대한 인식을 SwiftUI의 TapGesture에서는 지원하지 않고 있어요.

    그렇기에 이런식의 사용이 필요하죠.

     

    또한, Coordinator 패턴을 통해 제스처 이벤트 처리를 도와주고 SwiftUI의 선언적 구문과 함께 편리하고 사용할 수 있죠.

     

    사실, UIGestureRecognizerRepresentable가 없어도 우리는 UIKit의 제스처를 사용할 수 있었는데요.

    UIViewRepresentable을 통해 UIView를 구성할때 거기서 제스처에 대해 넣어 설정 구현해주고 우리는 그 컨버팅된 View를 SwiftUI에서 사용할 수 있는 방법이였죠.

     

    다만, 위 예시에서와 같이 한 손가락 탭과 두 손가락 탭의 메서드를 달리 사용하는 등에서는 어떻게 보면 래핑을 한것이기에 버전에 따라 한 제스처가 묻히는 경우가 있습니다.

    현재 코드에 적용된다면 onTapGesture는 두 손가락 제스처를 구현한 UIKit의 인터랙션 동작과 충돌할 수 있는것이죠.

     

    그렇기에 iOS 18에서 도입된 UIGestureRecognizerRepresentable를 사용하면 이런 제스처 충돌을 해결할 수 있어요.

    보다 더 안전하고 편리하게 SwiftUI와 UIKit 제스처를 통합할 수 있는것이죠.

     

    실제 이 UIGestureRecognizerRepresentable는 다음과 같은 상황들에서 아주 유용하게 사용될거에요.

     

    1️⃣ SwiftUI에서 기본 제공하지 않는 복잡한 제스처 처리

    2️⃣ UIKit의 기존 제스처 로직을 SwiftUI로 마이그레이션

    3️⃣ 커스텀한 제스처 인식기 구현

     

    특히 저는 1번이 가장 와닿는것 같습니다.

     


    마무리

    UIGestureRecognizerRepresentable를 잘 활용하면 SwiftUI에서도 UIKit의 다양한 제스처 시스템을 활용할 수 있어요.

    정말 다양한 멀티터치, 회전, 속도 기반 스와이프와 같은 복잡한 제스처들이 필요한데 SwiftUI로 뷰 드로잉 하고 있다면 도움이 많이 될 포인트라고 생각됩니다.

     


    레퍼런스

     

    UIGestureRecognizerRepresentable | Apple Developer Documentation

    A wrapper for a that you use to integrate that gesture recognizer into your SwiftUI hierarchy.

    developer.apple.com

     

    Customizing Gestures in SwiftUI | Fatbobman's Blog

    This article shows how to customize gestures in SwiftUI. It covers creating swipe, press, and click gestures, as well as using view modifiers and GestureState.

    fatbobman.com

Designed by Tistory.