From 35000dcb0f381a478ae6248ceab62b1ee7d9b5b0 Mon Sep 17 00:00:00 2001 From: Philip Lindberg Date: Sat, 15 Feb 2020 09:22:07 +0100 Subject: [PATCH 1/7] Change annotation priority (#222) --- ios/Classes/MapboxMapController.swift | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index 3bf3443b7..c83973169 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -340,6 +340,11 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma camera.pitch = initialTilt mapView.setCamera(camera, animated: false) } + + lineAnnotationController = MGLLineAnnotationController(mapView: self.mapView) + lineAnnotationController!.annotationsInteractionEnabled = true + lineAnnotationController?.delegate = self + symbolAnnotationController = MGLSymbolAnnotationController(mapView: self.mapView) symbolAnnotationController!.annotationsInteractionEnabled = true symbolAnnotationController?.delegate = self @@ -347,10 +352,6 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma circleAnnotationController = MGLCircleAnnotationController(mapView: self.mapView) circleAnnotationController!.annotationsInteractionEnabled = true circleAnnotationController?.delegate = self - - lineAnnotationController = MGLLineAnnotationController(mapView: self.mapView) - lineAnnotationController!.annotationsInteractionEnabled = true - lineAnnotationController?.delegate = self mapReadyResult?(nil) if let channel = channel { From c5b8d8e9d72c6d68ea1dd989522278aa2987e8a4 Mon Sep 17 00:00:00 2001 From: m0nac0 <58807793+m0nac0@users.noreply.github.com> Date: Sat, 15 Feb 2020 09:23:06 +0100 Subject: [PATCH 2/7] Update README: Access Tokens for self-hosted tiles (#217) * Update Readme: access tokens in projects not using Mapbox tiles * Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 41efc74df..a723ee01e 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ We're compiling a list of apps using this SDK. If you want to be listed here, pl #### Mapbox Access Token This project uses Mapbox vector tiles, which requires a Mapbox account and a Mapbox access token. Obtain a free access token on [your Mapbox account page](https://www.mapbox.com/account/access-tokens/). +> **Even if you do not use Mapbox vector tiles but vector tiles from a different source (like self-hosted tiles) with this plugin, you will need to specify any non-empty string as Access Token as explained below!** ##### Android Add Mapbox read token value in the application manifest ```android/app/src/main/AndroidManifest.xml:``` From 21df130a33a8984c7e07dbef4f483b04e2d45044 Mon Sep 17 00:00:00 2001 From: Alexander V Date: Sat, 15 Feb 2020 09:23:41 +0100 Subject: [PATCH 3/7] Returned a nil result so the future completes. (#216) --- ios/Classes/MapboxMapController.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index c83973169..7990315b6 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -117,12 +117,14 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma if let camera = Convert.parseCameraUpdate(cameraUpdate: cameraUpdate, mapView: mapView) { mapView.setCamera(camera, animated: false) } + result(nil) case "camera#animate": guard let arguments = methodCall.arguments as? [String: Any] else { return } guard let cameraUpdate = arguments["cameraUpdate"] as? [Any] else { return } if let camera = Convert.parseCameraUpdate(cameraUpdate: cameraUpdate, mapView: mapView) { mapView.setCamera(camera, animated: true) } + result(nil) case "symbol#add": guard let symbolAnnotationController = symbolAnnotationController else { return } guard let arguments = methodCall.arguments as? [String: Any] else { return } From 462311934217c83a88ce26bde9dce5daec3ef21d Mon Sep 17 00:00:00 2001 From: Nathan Hamblen Date: Sat, 15 Feb 2020 03:28:13 -0500 Subject: [PATCH 4/7] Fix missing location indicator on iOS (#176) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As noted in issue #138, the default user location indicator is not appearing in accordance with the `myLocationRenderMode` setting. Instead, no indication of the user location appears when that location is within the displayed map. This is the relevant API documentation for the method used to override annotation views: > The user location annotation view can also be customized via this > method. When annotation is an instance of `MGLUserLocation` (or equal > to the map view’s `userLocation` property), return an instance of > `MGLUserLocationAnnotationView` (or a subclass thereof). https://docs.mapbox.com/ios/api/maps/5.6.1/Protocols/MGLMapViewDelegate.html#/Managing%20Annotation%20Views From that it sounds like this controller behaves correctly by returning "an instance" of `MGLUserLocation`, but perhaps the assumption is that this instance will provide a specialized implementation. I wasn't able to find any more information on this. However, the return value for this function is optional. I found that returning `nil` when a MGLUserLocation is requested resulted in the location displaying with a dot as expected. Note: `MyLocationRenderMode.COMPASS` is not supported, and as far as I can tell it is not implemented within the Mapbox iOS SDK. Only a blue dot with no direction arrow is provided. Other render modes may require a custom iOS implementation in flutter-mapbox-gl. --- ios/Classes/MapboxMapController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index 7990315b6..5699c563c 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -325,7 +325,7 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma // This is required in order to hide the default Maps SDK pin func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? { if annotation is MGLUserLocation { - return MGLUserLocationAnnotationView() + return nil } return MGLAnnotationView(frame: CGRect(x: 0, y: 0, width: 10, height: 10)) } From eeb130af28f60030c3feccb08e8c1aa73b2a7594 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Sat, 15 Feb 2020 09:43:50 +0100 Subject: [PATCH 5/7] [example] add full page map example (#201) --- example/lib/full_map.dart | 40 +++++++++++++++++++++++++++++++++++++++ example/lib/main.dart | 3 +++ 2 files changed, 43 insertions(+) create mode 100644 example/lib/full_map.dart diff --git a/example/lib/full_map.dart b/example/lib/full_map.dart new file mode 100644 index 000000000..ee9b42950 --- /dev/null +++ b/example/lib/full_map.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:mapbox_gl/mapbox_gl.dart'; + +import 'page.dart'; + +class FullMapPage extends Page { + FullMapPage() + : super(const Icon(Icons.map), 'Full screen map'); + + @override + Widget build(BuildContext context) { + return const FullMap(); + } +} + +class FullMap extends StatefulWidget { + const FullMap(); + + @override + State createState() => FullMapState(); +} + +class FullMapState extends State { + MapboxMapController mapController; + + void _onMapCreated(MapboxMapController controller) { + mapController = controller; + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + body: MapboxMap( + onMapCreated: _onMapCreated, + initialCameraPosition: + const CameraPosition(target: LatLng(0.0, 0.0)), + ) + ); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index e81ce1804..4fec3b987 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -4,8 +4,10 @@ import 'package:flutter/material.dart'; import 'package:location/location.dart'; +import 'package:mapbox_gl_example/full_map.dart'; import 'animate_camera.dart'; +import 'full_map.dart'; import 'line.dart'; import 'map_ui.dart'; import 'move_camera.dart'; @@ -16,6 +18,7 @@ import 'scrolling_map.dart'; final List _allPages = [ MapUiPage(), + FullMapPage(), AnimateCameraPage(), MoveCameraPage(), PlaceSymbolPage(), From c378a3053fca874b9abf8f17a940f5f661428a29 Mon Sep 17 00:00:00 2001 From: Nathan Hamblen Date: Sat, 15 Feb 2020 05:08:10 -0500 Subject: [PATCH 6/7] Provide `onMapIdle` callback (#214) Corresponding to `mapViewDidBecomeIdle` in the iOS SDK, this informs the application "that the map view is entering an idle state, and no more drawing will be necessary until new data is loaded or there is some interaction with the map." https://docs.mapbox.com/ios/api/maps/5.6.1/Protocols/MGLMapViewDelegate.html#/c:objc(pl)MGLMapViewDelegate(im)mapViewDidBecomeIdle: I have not provided an Android implementation as I am not set up to test one yet. I would do this later if it's still missing. --- ios/Classes/MapboxMapController.swift | 6 ++++++ lib/src/controller.dart | 18 +++++++++++++++--- lib/src/mapbox_map.dart | 12 +++++++++++- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index 5699c563c..4e83699d0 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -430,6 +430,12 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } } + func mapViewDidBecomeIdle(_ mapView: MGLMapView) { + if let channel = channel { + channel.invokeMethod("map#onIdle", arguments: []); + } + } + func mapView(_ mapView: MGLMapView, regionWillChangeAnimated animated: Bool) { if let channel = channel { channel.invokeMethod("camera#onMoveStarted", arguments: []); diff --git a/lib/src/controller.dart b/lib/src/controller.dart index cf0f7156b..104aab2cd 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -11,6 +11,8 @@ typedef void OnStyleLoadedCallback(); typedef void OnCameraTrackingDismissedCallback(); typedef void OnCameraTrackingChangedCallback(MyLocationTrackingMode mode); +typedef void OnMapIdleCallback(); + /// Controller for a single MapboxMap instance running on the host platform. /// /// Change listeners are notified upon changes to any of @@ -32,7 +34,8 @@ class MapboxMapController extends ChangeNotifier { {this.onStyleLoadedCallback, this.onMapClick, this.onCameraTrackingDismissed, - this.onCameraTrackingChanged}) + this.onCameraTrackingChanged, + this.onMapIdle}) : assert(_id != null), assert(channel != null), _channel = channel { @@ -45,7 +48,8 @@ class MapboxMapController extends ChangeNotifier { {OnStyleLoadedCallback onStyleLoadedCallback, OnMapClickCallback onMapClick, OnCameraTrackingDismissedCallback onCameraTrackingDismissed, - OnCameraTrackingChangedCallback onCameraTrackingChanged}) async { + OnCameraTrackingChangedCallback onCameraTrackingChanged, + OnMapIdleCallback onMapIdle}) async { assert(id != null); final MethodChannel channel = MethodChannel('plugins.flutter.io/mapbox_maps_$id'); @@ -54,7 +58,8 @@ class MapboxMapController extends ChangeNotifier { onStyleLoadedCallback: onStyleLoadedCallback, onMapClick: onMapClick, onCameraTrackingDismissed: onCameraTrackingDismissed, - onCameraTrackingChanged: onCameraTrackingChanged); + onCameraTrackingChanged: onCameraTrackingChanged, + onMapIdle: onMapIdle); } final MethodChannel _channel; @@ -66,6 +71,8 @@ class MapboxMapController extends ChangeNotifier { final OnCameraTrackingDismissedCallback onCameraTrackingDismissed; final OnCameraTrackingChangedCallback onCameraTrackingChanged; + final OnMapIdleCallback onMapIdle; + /// Callbacks to receive tap events for symbols placed on this map. final ArgumentCallbacks onSymbolTapped = ArgumentCallbacks(); @@ -175,6 +182,11 @@ class MapboxMapController extends ChangeNotifier { onCameraTrackingDismissed(); } break; + case 'map#onIdle': + if (onMapIdle != null) { + onMapIdle(); + } + break; default: throw MissingPluginException(); } diff --git a/lib/src/mapbox_map.dart b/lib/src/mapbox_map.dart index eedcda940..6cf587667 100644 --- a/lib/src/mapbox_map.dart +++ b/lib/src/mapbox_map.dart @@ -31,6 +31,7 @@ class MapboxMap extends StatefulWidget { this.onMapClick, this.onCameraTrackingDismissed, this.onCameraTrackingChanged, + this.onMapIdle, }) : assert(initialCameraPosition != null); final MapCreatedCallback onMapCreated; @@ -130,6 +131,14 @@ class MapboxMap extends StatefulWidget { final OnCameraTrackingDismissedCallback onCameraTrackingDismissed; final OnCameraTrackingChangedCallback onCameraTrackingChanged; + /// Called when map view is entering an idle state, and no more drawing will + /// be necessary until new data is loaded or there is some interaction with + /// the map. + /// * No camera transitions are in progress + /// * All currently requested tiles have loaded + /// * All fade/transition animations have completed + final OnMapIdleCallback onMapIdle; + @override State createState() => _MapboxMapState(); } @@ -198,7 +207,8 @@ class _MapboxMapState extends State { onStyleLoadedCallback: widget.onStyleLoadedCallback, onMapClick: widget.onMapClick, onCameraTrackingDismissed: widget.onCameraTrackingDismissed, - onCameraTrackingChanged: widget.onCameraTrackingChanged); + onCameraTrackingChanged: widget.onCameraTrackingChanged, + onMapIdle: widget.onMapIdle); _controller.complete(controller); if (widget.onMapCreated != null) { widget.onMapCreated(controller); From 16439ed8da46576b9af537aa8424d0abf08268e4 Mon Sep 17 00:00:00 2001 From: Nathan Hamblen Date: Sat, 15 Feb 2020 05:09:22 -0500 Subject: [PATCH 7/7] Support setting map's content insets (#215) This allows the maps center (corresponding to a user location, or any given coordinate) to be automatically offset to account for content that is inset within the map. https://docs.mapbox.com/ios/api/maps/5.6.1/Classes/MGLMapView.html#/c:objc(cs)MGLMapView(im)setContentInset:animated:completionHandler: --- ios/Classes/MapboxMapController.swift | 15 +++++++++++++++ lib/src/controller.dart | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index 4e83699d0..f663cb5fc 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -90,6 +90,21 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma style.localizeLabels(into: nil) } result(nil) + case "map#updateContentInsets": + guard let arguments = methodCall.arguments as? [String: Any] else { return } + + if let bounds = arguments["bounds"] as? [String: Any], + let top = bounds["top"] as? CGFloat, + let left = bounds["left"] as? CGFloat, + let bottom = bounds["bottom"] as? CGFloat, + let right = bounds["right"] as? CGFloat, + let animated = arguments["animated"] as? Bool { + mapView.setContentInset(UIEdgeInsets(top: top, left: left, bottom: bottom, right: right), animated: animated) { + result(nil) + } + } else { + result(nil) + } case "map#setMapLanguage": guard let arguments = methodCall.arguments as? [String: Any] else { return } if let localIdentifier = arguments["language"] as? String, let style = mapView.style { diff --git a/lib/src/controller.dart b/lib/src/controller.dart index 104aab2cd..ccca05c46 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -255,6 +255,30 @@ class MapboxMapController extends ChangeNotifier { await _channel.invokeMethod('map#matchMapLanguageWithDeviceDefault'); } + /// Updates the distance from the edges of the map view’s frame to the edges + /// of the map view’s logical viewport, optionally animating the change. + /// + /// When the value of this property is equal to `EdgeInsets.zero`, viewport + /// properties such as centerCoordinate assume a viewport that matches the map + /// view’s frame. Otherwise, those properties are inset, excluding part of the + /// frame from the viewport. For instance, if the only the top edge is inset, + /// the map center is effectively shifted downward. + /// + /// The returned [Future] completes after the change has been made on the + /// platform side. + Future updateContentInsets(EdgeInsets insets, + [bool animated = false]) async { + await _channel.invokeMethod('map#updateContentInsets', { + 'bounds': { + 'top': insets.top, + 'left': insets.left, + 'bottom': insets.bottom, + 'right': insets.right, + }, + 'animated': animated, + }); + } + /// Updates the language of the map labels to match the specified language. /// Supported language strings are available here: https://github.com/mapbox/mapbox-plugins-android/blob/e29c18d25098eb023a831796ff807e30d8207c36/plugin-localization/src/main/java/com/mapbox/mapboxsdk/plugins/localization/MapLocale.java#L39-L87 ///