Flutter Tap Gestures not working with UiKitView and MapBox

199 views
Skip to first unread message

Jonty Lisher

unread,
Oct 31, 2019, 6:59:02 AM10/31/19
to Flutter Development (flutter-dev)

I'm trying to find the best way of using MapBox with Flutter and UiKitView/AndroidView seemed like a good approach.


I've managed to setup a UiKitView that loads MapBox with an annotation and polyline drawn however trying to use some gestures that MapBox allow for such as tapping on an annotation to show the callout or placing an annotation on the map by using long press gesture doesn't work. I don't see any errors or anything whilst the apps running so it's hard to tell if somethings going wrong or it's just not doing anything.


Some Gestures do work such as panning the map or double tapping to zoom in but I want to get all or atleast most of the functionality from MapBox. I've also tried just returning a normal UIView for the UiKitView and passing gestures but I didn't have any luck with that either so I assume I'm not handling the gestures properly.


Below is the UiKitView implementation


class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Map App'),
        ),
        body: Container(
          child: Center(
              child: SizedBox(
                  height: double.infinity, width: double.infinity, child: MapBoxUIKitView())
              ),
        ),
      ),
    );
  }
}

class MapBoxUIKitView extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return MapBoxUIKitViewState();
  }
}

class MapBoxUIKitViewState extends State<MapBoxUIKitView> {
  @override
  Widget build(BuildContext context) {
    return UiKitView(
      viewType: "com.mapapp/mapbox_uikitview",
      gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>[
        new Factory<OneSequenceGestureRecognizer>(
            () => new EagerGestureRecognizer())
      ].toSet(),
    );
  }
}


Below is the AppDelegate.swift


import UIKit
import Flutter
import Mapbox

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)

    let mapBoxViewFactory = MapBoxViewFactory()
    registrar(forPlugin: "MapApp").register(mapBoxViewFactory, withId: "com.mapapp/mapbox_uikitview")

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

public class MapBoxViewFactory : NSObject, FlutterPlatformViewFactory {
    public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
        return MapBoxView(frame, viewId: viewId, args: args)
    }
}

public class MapBoxView : NSObject, FlutterPlatformView, MGLMapViewDelegate {
    let frame: CGRect
    let viewId: Int64
    var mapView: MGLMapView!

    init(_ frame: CGRect, viewId: Int64, args: Any?) {
        self.frame = frame
        self.viewId = viewId
    }

    public func view() -> UIView {
        let url = URL(string: "mapbox://styles/mapbox/streets-v11")
        mapView = MGLMapView(frame: frame, styleURL: url)
        mapView.delegate = self

        mapView.setCenter(CLLocationCoordinate2D(latitude: 45.522585, longitude: -122.685699), zoomLevel: 9, animated: false)

        var coordinates = [
        CLLocationCoordinate2D(latitude: 45.522585, longitude: -122.685699),
        CLLocationCoordinate2D(latitude: 45.534611, longitude: -122.708873),
        CLLocationCoordinate2D(latitude: 45.530883, longitude: -122.678833),
        CLLocationCoordinate2D(latitude: 45.547115, longitude: -122.667503),
        CLLocationCoordinate2D(latitude: 45.530643, longitude: -122.660121)
        ]

        let shape = MGLPolylineFeature(coordinates: &coordinates, count: UInt(coordinates.count))
        let source = MGLShapeSource(identifier: "route-source", features: [shape], options: nil)

        let lineStyle = MGLLineStyleLayer(identifier: "route-style", source: source)
        lineStyle.lineColor = NSExpression(forConstantValue: #colorLiteral(red: 0.1897518039, green: 0.3010634184, blue: 0.7994888425, alpha: 1))
        lineStyle.lineWidth = NSExpression(forConstantValue: 3)

        mapView.style?.addSource(source)
        mapView.style?.addLayer(lineStyle)

        mapView.addAnnotation(shape)
        let annotation = MGLPointAnnotation()
        annotation.coordinate = CLLocationCoordinate2D(latitude: 45.522585, longitude: -122.685699)
        annotation.title = "Annotation"
        mapView.addAnnotation(annotation)

        let longPress = UILongPressGestureRecognizer(target: self, action: #selector(didLongPress(_:)))
        mapView.addGestureRecognizer(longPress)

        return mapView
    }

    // Implement the delegate method that allows annotations to show callouts when tapped
    func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
        return true
    }

    @objc func didLongPress(_ sender: UILongPressGestureRecognizer) {
        guard sender.state == .began else { return }

            let point = sender.location(in: mapView)
            let coordinate = mapView.convert(point, toCoordinateFrom: mapView)

            let annotation = MGLPointAnnotation()
            annotation.coordinate = coordinate
            annotation.title = "Long Press"
            mapView.addAnnotation(annotation)
    }
}


Sorry for the all the code but I thought it would be useful to show it all. Thanks

Reply all
Reply to author
Forward
0 new messages