diff --git a/android/src/main/java/com/mapbox/mapboxgl/Convert.java b/android/src/main/java/com/mapbox/mapboxgl/Convert.java index f22b9d068..d4b9e3954 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/Convert.java +++ b/android/src/main/java/com/mapbox/mapboxgl/Convert.java @@ -260,6 +260,11 @@ static void interpretMapboxMapOptions(Object o, MapboxMapOptionsSink sink, Conte if (myLocationRenderMode != null) { sink.setMyLocationRenderMode(toInt(myLocationRenderMode)); } + final Object myLocationStyle = data.get("myLocationStyle"); + if (myLocationStyle != null) { + final Map myLocationStyleData = toMap(myLocationStyle); + sink.setMyLocationStyle(myLocationStyleData); + } final Object logoViewMargins = data.get("logoViewMargins"); if (logoViewMargins != null) { final List logoViewMarginsData = toList(logoViewMargins); diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java index a7a27e866..05bf4b969 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java @@ -11,6 +11,8 @@ import com.mapbox.mapboxsdk.maps.MapboxMapOptions; import com.mapbox.mapboxsdk.maps.Style; import io.flutter.plugin.common.BinaryMessenger; +import java.util.Collections; +import java.util.Map; class MapboxMapBuilder implements MapboxMapOptionsSink { public final String TAG = getClass().getSimpleName(); @@ -21,6 +23,7 @@ class MapboxMapBuilder implements MapboxMapOptionsSink { private int myLocationTrackingMode = 0; private int myLocationRenderMode = 0; private String styleString = Style.MAPBOX_STREETS; + private Map myLocationStyle = Collections.emptyMap(); private LatLngBounds bounds = null; MapboxMapController build( @@ -44,7 +47,7 @@ MapboxMapController build( controller.setMyLocationTrackingMode(myLocationTrackingMode); controller.setMyLocationRenderMode(myLocationRenderMode); controller.setTrackCameraPosition(trackCameraPosition); - + controller.setMyLocationStyle(myLocationStyle); if (null != bounds) { controller.setCameraTargetBounds(bounds); } @@ -122,6 +125,11 @@ public void setMyLocationRenderMode(int myLocationRenderMode) { this.myLocationRenderMode = myLocationRenderMode; } + @Override + public void setMyLocationStyle(Map myLocationStyle) { + this.myLocationStyle = myLocationStyle; + } + public void setLogoViewMargins(int x, int y) { options.logoMargins( new int[] { diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index fa1b851a6..5af4aac96 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -11,6 +11,7 @@ import android.content.res.AssetFileDescriptor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Color; import android.graphics.PointF; import android.graphics.RectF; import android.location.Location; @@ -127,6 +128,7 @@ final class MapboxMapController private Set interactiveFeatureLayerIds; private Map addedFeaturesByLayer; + private Map myLocationStyle; private LatLngBounds bounds = null; @@ -148,6 +150,7 @@ final class MapboxMapController this.interactiveFeatureLayerIds = new HashSet<>(); this.addedFeaturesByLayer = new HashMap(); this.density = context.getResources().getDisplayMetrics().density; + this.myLocationStyle = Collections.emptyMap(); this.lifecycleProvider = lifecycleProvider; if (dragEnabled) { this.androidGesturesManager = new AndroidGesturesManager(this.mapView.getContext(), false); @@ -314,6 +317,14 @@ private LocationComponentOptions buildLocationComponentOptions(Style style) { final LocationComponentOptions.Builder optionsBuilder = LocationComponentOptions.builder(context); optionsBuilder.trackingGesturesManagement(true); + if (myLocationStyle.get("puckColor") != null) { + final int color = Color.parseColor((String) myLocationStyle.get("puckColor")); + optionsBuilder.foregroundTintColor(color); + } + if (myLocationStyle.get("pulsingColor") != null) { + final int color = Color.parseColor((String) myLocationStyle.get("pulsingColor")); + optionsBuilder.accuracyColor(color); + } final String lastLayerId = getLastLayerOnStyle(style); if (lastLayerId != null) { @@ -1403,6 +1414,12 @@ public void setMyLocationRenderMode(int myLocationRenderMode) { } } + @Override + public void setMyLocationStyle(Map myLocationStyle) { + this.myLocationStyle = myLocationStyle; + updateLocationComponentLayer(); + } + public void setLogoViewMargins(int x, int y) { mapboxMap.getUiSettings().setLogoMargins(x, 0, 0, y); } diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapOptionsSink.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapOptionsSink.java index bcc8e6b48..f889ed0a0 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapOptionsSink.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapOptionsSink.java @@ -5,6 +5,7 @@ package com.mapbox.mapboxgl; import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import java.util.Map; /** Receiver of MapboxMap configuration options. */ interface MapboxMapOptionsSink { @@ -34,6 +35,8 @@ void setCameraTargetBounds( void setMyLocationRenderMode(int myLocationRenderMode); + void setMyLocationStyle(Map myLocationStyle); + void setLogoViewMargins(int x, int y); void setCompassGravity(int gravity); diff --git a/example/lib/custom_my_location_style.dart b/example/lib/custom_my_location_style.dart new file mode 100644 index 000000000..9e0f44482 --- /dev/null +++ b/example/lib/custom_my_location_style.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:location/location.dart'; +import 'package:mapbox_gl_example/main.dart'; +import 'package:mapbox_gl_example/page.dart'; +import 'package:mapbox_gl/mapbox_gl.dart'; + +class CustomMyLocationStyle extends ExamplePage { + const CustomMyLocationStyle({Key? key}) + : super(const Icon(Icons.my_location), "Custom my location style"); + + @override + Widget build(BuildContext context) { + return CustomMyLocationStyleBody(); + } +} + +class CustomMyLocationStyleBody extends StatefulWidget { + const CustomMyLocationStyleBody({Key? key}) : super(key: key); + + @override + State createState() => + _CustomMyLocationStyleBodyState(); +} + +class _CustomMyLocationStyleBodyState extends State { + var _myLocationStyle = MyLocationStyle(); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: MapboxMap( + initialCameraPosition: CameraPosition(target: LatLng(0, 0)), + accessToken: MapsDemo.ACCESS_TOKEN, + myLocationEnabled: true, + myLocationStyle: _myLocationStyle, + onMapCreated: (ctr) async { + final location = await Location().getLocation(); + await ctr.animateCamera(CameraUpdate.newLatLngZoom( + LatLng(location.latitude ?? 0, location.longitude ?? 0), 14)); + }, + ), + floatingActionButton: FloatingActionButton( + child: Icon(Icons.swap_horiz), + onPressed: () { + setState(() { + _myLocationStyle = MyLocationStyle( + puckColor: Colors.yellow, + pulsingColor: Colors.green, + ); + }); + }, + ), + ); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index cd8a62c66..2d41a6552 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:location/location.dart'; import 'package:mapbox_gl_example/custom_marker.dart'; +import 'package:mapbox_gl_example/custom_my_location_style.dart'; import 'package:mapbox_gl_example/full_map.dart'; import 'package:mapbox_gl_example/offline_regions.dart'; import 'package:mapbox_gl_example/place_batch.dart'; @@ -49,7 +50,8 @@ final List _allPages = [ CustomMarkerPage(), BatchAddPage(), ClickAnnotationPage(), - Sources() + Sources(), + CustomMyLocationStyle(), ]; class MapsDemo extends StatefulWidget { diff --git a/ios/Classes/Convert.swift b/ios/Classes/Convert.swift index fb1a521c5..918f1a688 100644 --- a/ios/Classes/Convert.swift +++ b/ios/Classes/Convert.swift @@ -48,6 +48,9 @@ class Convert { { delegate.setMyLocationRenderMode(myLocationRenderMode: renderMode) } + if let myLocationStyle = options["myLocationStyle"] as? [String: String] { + delegate.setMyLocationStyle(style: myLocationStyle) + } if let logoViewMargins = options["logoViewMargins"] as? [Double] { delegate.setLogoViewMargins(x: logoViewMargins[0], y: logoViewMargins[1]) } diff --git a/ios/Classes/MapboxMapController.swift b/ios/Classes/MapboxMapController.swift index 1ac3fa4a5..52ce182c8 100644 --- a/ios/Classes/MapboxMapController.swift +++ b/ios/Classes/MapboxMapController.swift @@ -28,6 +28,8 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma private var interactiveFeatureLayerIds = Set() private var addedShapesByLayer = [String: MGLShape]() + private var userLocationAnnotationViewStyle = MGLUserLocationAnnotationViewStyle() + func view() -> UIView { return mapView } @@ -1285,6 +1287,12 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } } + func mapView(styleForDefaultUserLocationAnnotationView _: MGLMapView) + -> MGLUserLocationAnnotationViewStyle + { + return userLocationAnnotationViewStyle + } + func addSourceGeojson(sourceId: String, geojson: String) { do { let parsed = try MGLShape( @@ -1430,6 +1438,16 @@ class MapboxMapController: NSObject, FlutterPlatformView, MGLMapViewDelegate, Ma } } + func setMyLocationStyle(style: [String: String]) { + if let puckColor = UIColor(hexString: style["puckColor"] ?? "") { + userLocationAnnotationViewStyle.puckFillColor = puckColor + } + if let pulsingColor = UIColor(hexString: style["pulsingColor"] ?? "") { + userLocationAnnotationViewStyle.haloFillColor = pulsingColor + } + mapView.updateUserLocationAnnotationView() + } + func setLogoViewMargins(x: Double, y: Double) { mapView.logoViewMargins = CGPoint(x: x, y: y) } diff --git a/ios/Classes/MapboxMapOptionsSink.swift b/ios/Classes/MapboxMapOptionsSink.swift index c032baa15..6848a59fd 100644 --- a/ios/Classes/MapboxMapOptionsSink.swift +++ b/ios/Classes/MapboxMapOptionsSink.swift @@ -14,6 +14,7 @@ protocol MapboxMapOptionsSink { func setMyLocationEnabled(myLocationEnabled: Bool) func setMyLocationTrackingMode(myLocationTrackingMode: MGLUserTrackingMode) func setMyLocationRenderMode(myLocationRenderMode: MyLocationRenderMode) + func setMyLocationStyle(style: [String: String]) func setLogoViewMargins(x: Double, y: Double) func setCompassViewPosition(position: MGLOrnamentPosition) func setCompassViewMargins(x: Double, y: Double) diff --git a/lib/mapbox_gl.dart b/lib/mapbox_gl.dart index 0c836a3e5..ae830065b 100644 --- a/lib/mapbox_gl.dart +++ b/lib/mapbox_gl.dart @@ -17,6 +17,7 @@ import 'package:mapbox_gl_platform_interface/mapbox_gl_platform_interface.dart'; export 'package:mapbox_gl_platform_interface/mapbox_gl_platform_interface.dart' show + MapBoxColorConversion, LatLng, LatLngBounds, LatLngQuad, @@ -32,6 +33,7 @@ export 'package:mapbox_gl_platform_interface/mapbox_gl_platform_interface.dart' MapboxStyles, MyLocationTrackingMode, MyLocationRenderMode, + MyLocationStyle, CompassViewPosition, AttributionButtonPosition, Annotation, @@ -56,6 +58,5 @@ part 'src/offline_region.dart'; part 'src/download_region_status.dart'; part 'src/layer_expressions.dart'; part 'src/layer_properties.dart'; -part 'src/color_tools.dart'; part 'src/annotation_manager.dart'; part 'src/util.dart'; diff --git a/lib/src/mapbox_map.dart b/lib/src/mapbox_map.dart index ffd86c02e..ab827c44d 100644 --- a/lib/src/mapbox_map.dart +++ b/lib/src/mapbox_map.dart @@ -30,6 +30,7 @@ class MapboxMap extends StatefulWidget { this.myLocationEnabled = false, this.myLocationTrackingMode = MyLocationTrackingMode.None, this.myLocationRenderMode = MyLocationRenderMode.COMPASS, + this.myLocationStyle = const MyLocationStyle(), this.logoViewMargins, this.compassViewPosition, this.compassViewMargins, @@ -167,6 +168,9 @@ class MapboxMap extends StatefulWidget { /// The mode to render the user location symbol final MyLocationRenderMode myLocationRenderMode; + /// The style of the user location annotation + final MyLocationStyle myLocationStyle; + /// Set the layout margins for the Mapbox Logo final Point? logoViewMargins; @@ -339,6 +343,7 @@ class _MapboxMapOptions { this.myLocationEnabled, this.myLocationTrackingMode, this.myLocationRenderMode, + this.myLocationStyle, this.logoViewMargins, this.compassViewPosition, this.compassViewMargins, @@ -362,6 +367,7 @@ class _MapboxMapOptions { myLocationEnabled: map.myLocationEnabled, myLocationTrackingMode: map.myLocationTrackingMode, myLocationRenderMode: map.myLocationRenderMode, + myLocationStyle: map.myLocationStyle, logoViewMargins: map.logoViewMargins, compassViewPosition: map.compassViewPosition, compassViewMargins: map.compassViewMargins, @@ -396,6 +402,8 @@ class _MapboxMapOptions { final MyLocationRenderMode? myLocationRenderMode; + final MyLocationStyle? myLocationStyle; + final Point? logoViewMargins; final CompassViewPosition? compassViewPosition; @@ -446,6 +454,7 @@ class _MapboxMapOptions { addIfNonNull('myLocationEnabled', myLocationEnabled); addIfNonNull('myLocationTrackingMode', myLocationTrackingMode?.index); addIfNonNull('myLocationRenderMode', myLocationRenderMode?.index); + addIfNonNull('myLocationStyle', myLocationStyle?.toJson()); addIfNonNull('logoViewMargins', pointToArray(logoViewMargins)); addIfNonNull('compassViewPosition', compassViewPosition?.index); addIfNonNull('compassViewMargins', pointToArray(compassViewMargins)); diff --git a/mapbox_gl_platform_interface/lib/mapbox_gl_platform_interface.dart b/mapbox_gl_platform_interface/lib/mapbox_gl_platform_interface.dart index bf59ae3bb..c560b962c 100644 --- a/mapbox_gl_platform_interface/lib/mapbox_gl_platform_interface.dart +++ b/mapbox_gl_platform_interface/lib/mapbox_gl_platform_interface.dart @@ -23,3 +23,5 @@ part 'src/fill.dart'; part 'src/ui.dart'; part 'src/mapbox_gl_platform_interface.dart'; part 'src/source_properties.dart'; +part 'src/my_location_style.dart'; +part 'src/color_tools.dart'; diff --git a/lib/src/color_tools.dart b/mapbox_gl_platform_interface/lib/src/color_tools.dart similarity index 87% rename from lib/src/color_tools.dart rename to mapbox_gl_platform_interface/lib/src/color_tools.dart index f78a5a1c8..423c826f9 100644 --- a/lib/src/color_tools.dart +++ b/mapbox_gl_platform_interface/lib/src/color_tools.dart @@ -1,4 +1,4 @@ -part of mapbox_gl; +part of mapbox_gl_platform_interface; extension MapBoxColorConversion on Color { String toHexStringRGB() { diff --git a/mapbox_gl_platform_interface/lib/src/my_location_style.dart b/mapbox_gl_platform_interface/lib/src/my_location_style.dart new file mode 100644 index 000000000..0e47b5eb8 --- /dev/null +++ b/mapbox_gl_platform_interface/lib/src/my_location_style.dart @@ -0,0 +1,13 @@ +part of mapbox_gl_platform_interface; + +class MyLocationStyle { + final Color? puckColor; + final Color? pulsingColor; + + const MyLocationStyle({this.puckColor, this.pulsingColor}); + + dynamic toJson() => { + "puckColor": puckColor?.toHexStringRGB(), + "pulsingColor": pulsingColor?.toHexStringRGB(), + }..removeWhere((key, value) => value == null); +} diff --git a/mapbox_gl_web/lib/src/convert.dart b/mapbox_gl_web/lib/src/convert.dart index f51d40779..f280daa17 100644 --- a/mapbox_gl_web/lib/src/convert.dart +++ b/mapbox_gl_web/lib/src/convert.dart @@ -53,6 +53,9 @@ class Convert { if (options.containsKey('myLocationRenderMode')) { sink.setMyLocationRenderMode(options['myLocationRenderMode']); } + if (options.containsKey('myLocationStyle')) { + sink.setMyLocationStyle(options['myLocationStyle']); + } if (options.containsKey('logoViewMargins')) { sink.setLogoViewMargins( options['logoViewMargins'][0], options['logoViewMargins'][1]); diff --git a/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart b/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart index c08136cba..fe4ce2ba8 100644 --- a/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart +++ b/mapbox_gl_web/lib/src/mapbox_web_gl_platform.dart @@ -555,6 +555,11 @@ class MapboxWebGlPlatform extends MapboxGlPlatform print('myLocationRenderMode not available in web'); } + @override + void setMyLocationStyle(MyLocationStyle myLocationStyle) { + print('myLocationStyle not available in web'); + } + @override void setMyLocationTrackingMode(int myLocationTrackingMode) { if (_geolocateControl == null) { diff --git a/mapbox_gl_web/lib/src/options_sink.dart b/mapbox_gl_web/lib/src/options_sink.dart index e12f85a1e..0760623aa 100644 --- a/mapbox_gl_web/lib/src/options_sink.dart +++ b/mapbox_gl_web/lib/src/options_sink.dart @@ -27,6 +27,8 @@ abstract class MapboxMapOptionsSink { void setMyLocationRenderMode(int myLocationRenderMode); + void setMyLocationStyle(MyLocationStyle myLocationStyle); + void setLogoViewMargins(int x, int y); void setCompassAlignment(CompassViewPosition position);