mapkitkotlin-multiplatform

KMP MapKit Gesture detection


I am using Kotlin Multiplatform with MapKit-Compose and would like to keep track of user gestures on the map like zooming/pinching, panning, etc.

So I thought I could create the MapView and add the GestureRecognizers.

val mkMapView =
    remember {
        MKMapView().apply {
            // Init.....
            setZoomEnabled(true)
            setScrollEnabled(true)
            userInteractionEnabled = true

            setDelegate(delegate)
            delegate.addGestureRecognizer(mkMapView = this)
        }
    }
@OptIn(BetaInteropApi::class)
@ObjCAction
fun handleUserInteraction() {
    Logger.d("userZoomScrollOverride triggered")
}

@OptIn(BetaInteropApi::class)
@ObjCAction
fun handleMapPan(recognizer: UIPanGestureRecognizer) {
    Logger.d("userZoomScrollOverride handleMapPan")
}

fun addGestureRecognizer(mkMapView: MKMapView) {
    val panGesture = UIPanGestureRecognizer(target = this, action = NSSelectorFromString("handleMapPan:"))
    val pinchGesture = UIPinchGestureRecognizer(target = this, action = NSSelectorFromString("handleUserInteraction:"))
    val selector = UIGestureRecognizer(target = this, action = NSSelectorFromString("handleUserInteraction:"))
    mkMapView.addGestureRecognizer(selector)
    mkMapView.addGestureRecognizer(panGesture)
    mkMapView.addGestureRecognizer(pinchGesture)
}

Of course the handleUserInteraction/handleMapPan functions are never called. I never before tried working with NSSelectorFromString or anything like that, but it was the only thing I found on the Web.

Anybody that can point me into the right direction?


Solution

  • As Phil Dukhov pointed out, shouldRecognizeSimultaneouslyWithGestureRecognizer is required for the map to register these events.

    Define the delegate:

    class GestureDelegate :
        NSObject(),
        UIGestureRecognizerDelegateProtocol {
        override fun gestureRecognizer(
            gestureRecognizer: UIGestureRecognizer,
            shouldRecognizeSimultaneouslyWithGestureRecognizer: UIGestureRecognizer,
        ): Boolean {
            return true 
        }
    }
    

    Set the delegate and add the gestureRecognizer to the map:

        fun addGestureRecognizer(mkMapView: MKMapView) {
            val gestureDelegate = GestureDelegate()
    
            val panGesture = UIPanGestureRecognizer(target = this, action = NSSelectorFromString("handleMapPan:"))
            panGesture.delegate = gestureDelegate
    
            mkMapView.addGestureRecognizer(panGesture)
        }
    

    Handle the events:

        @OptIn(BetaInteropApi::class)
        @ObjCAction
        private fun handleMapPan(recognizer: UIPanGestureRecognizer) {
            Logger.d("Handling pan event.")
        }
    

    Thank you for the help!