For anyone wondering or searching for `MKMapView` ...
# compose-ios
r
For anyone wondering or searching for
MKMapView
embedding in a Composable in the future, because the previous examples did not have click handling (which survives garbage collection), here is my take on it:
Copy code
code in thread
Not perfect, if anyone sees anything to improve that would be great. It fits my use case of listening to a marker change from the hoisted state, but does not yet support center location / zoom change from the hoisted state.
❤️ 1
Copy code
@OptIn(ExperimentalForeignApi::class)
@Composable
fun AppleMapView( modifier: Modifier, centerPos: MapPos,  markerPos: MapPos?,  initialZoom: Float,  standard: Boolean,
    onClick: (ClickedLatLng) -> Unit,
) {
    val markerLocation = remember(markerPos) {
        if (markerPos != null) {
            CLLocationCoordinate2DMake(markerPos.lat, markerPos.long)
        } else {
            null
        }
    }
    val currZoom = remember(initialZoom) {    mutableStateOf(10_000.0 / initialZoom)  }
    val mkMapView = remember {
        MKMapView().apply {  setMapType(if (standard) MKMapTypeStandard else MKMapTypeSatellite) }
    }
    val mapGestureController = remember {
        MapGestureController(mkMapView) { lat, long ->  onClick(ClickedLatLng(lat, long))   }
    }
    val mapRegion = remember(centerPos, currZoom) {
        val latLongMeters = currZoom.value
        MKCoordinateRegionMakeWithDistance(centerCoordinate = CLLocationCoordinate2DMake(centerPos.lat, centerPos.long), latLongMeters, latLongMeters)
    }
    UIKitView(
        modifier = modifier,
        factory = {
            mkMapView.apply {
                mapGestureController.setupMapTapHandler()
                setRegion(mapRegion, animated = false)
            }
        },
        update = { mapView ->
            mapView.annotations.forEach { mapView.removeAnnotation(it as MKAnnotationProtocol) }
            if (markerLocation != null) {
                mapView.addAnnotations(listOf(MKPointAnnotation(markerLocation)))
            }
        }
    )
}
@OptIn(ExperimentalObjCName::class)
@ObjCName(name = "MapGestureController", swiftName = "MapGestureController", exact = true)
class MapGestureController(private val map: MKMapView, val onTapper: (latitude: Double, longitude: Double) -> Unit): NSObject() {
    @OptIn(ExperimentalForeignApi::class)
    fun setupMapTapHandler() {
        val mapView = map
        val tapRecognizer = UITapGestureRecognizer(target = this, action = sel_registerName("handleTap:"))
        mapView.addGestureRecognizer(tapRecognizer)
    }
    @OptIn(ExperimentalForeignApi::class, BetaInteropApi::class)
    @ObjCAction
    fun handleTap(recognizer: UITapGestureRecognizer) {
        val mapView = recognizer.view as? MKMapView ?: return
        val touchPoint = recognizer.locationInView(mapView)
        val coordsValue = mapView.convertPoint(touchPoint, toCoordinateFromView = mapView)
        coordsValue.useContents {
            onTapper(latitude, longitude)
        }
    }
}