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