Skip to content

Commit 473a546

Browse files
committed
fix: Marker and Annotation colors
It is now possible to provide a hue value to change the marker or pin annotation color. fixes #38
1 parent 866ff78 commit 473a546

File tree

8 files changed

+110
-41
lines changed

8 files changed

+110
-41
lines changed

example/ios/Podfile.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ SPEC CHECKSUMS:
1919

2020
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
2121

22-
COCOAPODS: 1.10.0
22+
COCOAPODS: 1.11.3

example/ios/Runner/Info.plist

+2
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,7 @@
4343
</array>
4444
<key>UIViewControllerBasedStatusBarAppearance</key>
4545
<false/>
46+
<key>CADisableMinimumFrameDurationOnPhone</key>
47+
<true/>
4648
</dict>
4749
</plist>

example/lib/place_annotation.dart

+32-8
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,31 @@ class PlaceAnnotationBodyState extends State<PlaceAnnotationBody> {
7979
_annotationIdCounter++;
8080
final AnnotationId annotationId = AnnotationId(annotationIdVal);
8181

82+
var bitMapDescriptor;
83+
84+
switch (iconType) {
85+
case 'marker':
86+
bitMapDescriptor = BitmapDescriptor.markerAnnotation;
87+
break;
88+
case 'pin':
89+
bitMapDescriptor = BitmapDescriptor.defaultAnnotation;
90+
break;
91+
case 'customAnnotationFromBytes':
92+
bitMapDescriptor = _iconFromBytes;
93+
break;
94+
case 'markerAnnotationWithHue':
95+
bitMapDescriptor = BitmapDescriptor.markerAnnotationWithHue(
96+
new Random().nextDouble() * 360);
97+
break;
98+
case 'defaultAnnotationWithColor':
99+
bitMapDescriptor = BitmapDescriptor.defaultAnnotationWithHue(
100+
new Random().nextDouble() * 360);
101+
break;
102+
}
103+
82104
final Annotation annotation = Annotation(
83105
annotationId: annotationId,
84-
icon: iconType == 'marker'
85-
? BitmapDescriptor.markerAnnotation
86-
: iconType == 'pin'
87-
? BitmapDescriptor.defaultAnnotation
88-
: iconType == 'customAnnotationFromBytes'
89-
? _iconFromBytes
90-
: _annotationIcon!,
106+
icon: bitMapDescriptor,
91107
position: LatLng(
92108
center.latitude + sin(_annotationIdCounter * pi / 6.0) / 20.0,
93109
center.longitude + cos(_annotationIdCounter * pi / 6.0) / 20.0,
@@ -97,7 +113,7 @@ class PlaceAnnotationBodyState extends State<PlaceAnnotationBody> {
97113
title: annotationIdVal,
98114
anchor: Offset(0.5, 0.0),
99115
snippet: '*',
100-
onTap: () => print('InfowWindow of id: $annotationId tapped.')),
116+
onTap: () => print('InfoWindow with id: $annotationId tapped.')),
101117
onTap: () {
102118
_onAnnotationTapped(annotationId);
103119
},
@@ -257,10 +273,18 @@ class PlaceAnnotationBodyState extends State<PlaceAnnotationBody> {
257273
child: const Text('add defaultAnnotation'),
258274
onPressed: () => _add('pin'),
259275
),
276+
TextButton(
277+
child: const Text('add defaultWithHue'),
278+
onPressed: () => _add('defaultAnnotationWithColor'),
279+
),
260280
TextButton(
261281
child: const Text('add markerAnnotation'),
262282
onPressed: () => _add('marker'),
263283
),
284+
TextButton(
285+
child: const Text('add markerWithHue'),
286+
onPressed: () => _add('markerAnnotationWithHue'),
287+
),
264288
TextButton(
265289
child: const Text('add customAnnotation'),
266290
onPressed: () => _add('customAnnotation'),

ios/Classes/Annotations/AnnotationController.swift

+19-10
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ extension AppleMapController: AnnotationDelegate {
2121
} else {
2222
annotation.selectedProgrammatically = false
2323
}
24-
24+
2525
if annotation.infoWindowConsumesTapEvents {
2626
let tapGestureRecognizer = InfoWindowTapGestureRecognizer(target: self, action: #selector(onCalloutTapped))
2727
tapGestureRecognizer.annotationId = annotation.id
@@ -30,7 +30,7 @@ extension AppleMapController: AnnotationDelegate {
3030
}
3131
}
3232
}
33-
33+
3434
public func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
3535
if annotation is MKUserLocation {
3636
return nil
@@ -39,7 +39,7 @@ extension AppleMapController: AnnotationDelegate {
3939
}
4040
return nil
4141
}
42-
42+
4343
func getAnnotationView(annotation: FlutterAnnotation) -> MKAnnotationView {
4444
let identifier: String = annotation.id
4545
var annotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
@@ -166,7 +166,7 @@ extension AppleMapController: AnnotationDelegate {
166166
}
167167
}
168168
}
169-
169+
170170
@objc func onCalloutTapped(infoWindowTap: InfoWindowTapGestureRecognizer) {
171171
if infoWindowTap.annotationId != nil && self.currentlySelectedAnnotation == infoWindowTap.annotationId! {
172172
self.channel.invokeMethod("infoWindow#onTap", arguments: ["annotationId": infoWindowTap.annotationId])
@@ -179,7 +179,7 @@ extension AppleMapController: AnnotationDelegate {
179179
private func getAnnotation(with id: String) -> FlutterAnnotation? {
180180
return self.mapView.annotations.filter { annotation in return (annotation as? FlutterAnnotation)?.id == id }.first as? FlutterAnnotation
181181
}
182-
182+
183183
private func annotationExists(with id: String) -> Bool {
184184
return self.getAnnotation(with: id) != nil
185185
}
@@ -188,7 +188,7 @@ extension AppleMapController: AnnotationDelegate {
188188
let annotation: FlutterAnnotation = FlutterAnnotation(fromDictionary: annotationData, registrar: registrar)
189189
self.addAnnotation(annotation: annotation)
190190
}
191-
191+
192192
/**
193193
Checks if an Annotation with the same id exists and removes it before adding if necessary
194194
- Parameter annotation: the FlutterAnnotation that should be added
@@ -203,15 +203,15 @@ extension AppleMapController: AnnotationDelegate {
203203
}
204204
self.mapView.addAnnotation(annotation)
205205
}
206-
206+
207207
private func getNextAnnotationZIndex() -> Double {
208208
let mapViewAnnotations = self.mapView.getMapViewAnnotations()
209209
if mapViewAnnotations.isEmpty {
210210
return 0;
211211
}
212212
return (mapViewAnnotations.last??.zIndex ?? 0) + 1
213213
}
214-
214+
215215
private func isAnnoationInFront(zIndex: Double) -> Bool {
216216
return (self.mapView.getMapViewAnnotations().last??.zIndex ?? 0) == zIndex
217217
}
@@ -224,8 +224,12 @@ extension AppleMapController: AnnotationDelegate {
224224
} else {
225225
pinAnnotationView = MKPinAnnotationView.init(annotation: annotation, reuseIdentifier: id)
226226
}
227-
228227
pinAnnotationView.layer.zPosition = annotation.zIndex
228+
229+
if let hueColor: Double = annotation.icon.hueColor {
230+
pinAnnotationView.pinTintColor = UIColor.init(hue: hueColor, saturation: 1, brightness: 1, alpha: 1)
231+
}
232+
229233
return pinAnnotationView
230234
}
231235

@@ -234,6 +238,11 @@ extension AppleMapController: AnnotationDelegate {
234238
self.mapView.register(FlutterMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: id)
235239
let markerAnnotationView: FlutterMarkerAnnotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: id, for: annotation) as! FlutterMarkerAnnotationView
236240
markerAnnotationView.stickyZPosition = annotation.zIndex
241+
242+
if let hueColor: Double = annotation.icon.hueColor {
243+
markerAnnotationView.markerTintColor = UIColor.init(hue: hueColor, saturation: 1, brightness: 1, alpha: 1)
244+
}
245+
237246
return markerAnnotationView
238247
}
239248

@@ -260,7 +269,7 @@ extension AppleMapController: AnnotationDelegate {
260269
private func getInfoWindowYOffset(annotationView: MKAnnotationView, annotation: FlutterAnnotation) -> CGFloat {
261270
return annotationView.frame.height * CGFloat(annotation.calloutOffset.y)
262271
}
263-
272+
264273
private func moveToFront(annotation: FlutterAnnotation) {
265274
let id: String = annotation.id
266275
annotation.zIndex = self.getNextAnnotationZIndex()

ios/Classes/Annotations/AnnotationIcon.swift

+8-1
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,20 @@ class AnnotationIcon: Equatable {
1616
var iconType: IconType
1717
var id: String
1818
var image: UIImage?
19+
var hueColor: Double?
1920

2021
public init(id: String, iconType: IconType) {
2122
self.iconType = iconType
2223
self.id = id
2324
}
2425

25-
public init(named name: String, id: String, iconScale: CGFloat? = 1.0) {
26+
public init(id: String, iconType: IconType, hueColor: Double) {
27+
self.iconType = iconType
28+
self.id = id
29+
self.hueColor = hueColor
30+
}
31+
32+
public init(withAsset name: String, id: String, iconScale: CGFloat? = 1.0) {
2633
self.iconType = .CUSTOM_FROM_ASSET
2734
self.id = id
2835
if let uiImage: UIImage = UIImage.init(named: name) {

ios/Classes/Annotations/FlutterAnnotation.swift

+5-4
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,19 @@ class FlutterAnnotation: NSObject, MKAnnotation {
6161

6262
static private func getAnnotationIcon(iconData: Array<Any>, registrar: FlutterPluginRegistrar, annotationId: String) -> AnnotationIcon {
6363
let iconTypeMap: Dictionary<String, IconType> = ["fromAssetImage": .CUSTOM_FROM_ASSET, "fromBytes": .CUSTOM_FROM_BYTES, "defaultAnnotation": .PIN, "markerAnnotation": .MARKER]
64-
var icon: AnnotationIcon
6564
let iconType: IconType = iconTypeMap[iconData[0] as! String] ?? .PIN
65+
var icon: AnnotationIcon = AnnotationIcon(id: annotationId, iconType: iconType)
6666
var scaleParam: CGFloat?
6767

6868
if iconType == .CUSTOM_FROM_ASSET {
6969
let assetPath: String = iconData[1] as! String
7070
scaleParam = CGFloat(iconData[2] as? Double ?? 1.0)
71-
icon = AnnotationIcon(named: registrar.lookupKey(forAsset: assetPath), id: annotationId, iconScale: scaleParam)
71+
icon = AnnotationIcon(withAsset: registrar.lookupKey(forAsset: assetPath), id: annotationId, iconScale: scaleParam)
7272
} else if iconType == .CUSTOM_FROM_BYTES {
7373
icon = AnnotationIcon(fromBytes: iconData[1] as! FlutterStandardTypedData, id: annotationId)
74-
}else {
75-
icon = AnnotationIcon(id: annotationId, iconType: iconType)
74+
} else if iconData.count > 1 {
75+
icon = AnnotationIcon(id: annotationId, iconType: iconType, hueColor: iconData[1] as! Double)
76+
7677
}
7778
return icon
7879
}

ios/Classes/MapView/FlutterMapView.swift

-2
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,6 @@ class FlutterMapView: MKMapView, UIGestureRecognizerDelegate {
271271
let flutterAnnotations = self.annotations as? [FlutterAnnotation] ?? []
272272
let sortedAnnotations = flutterAnnotations.sorted(by: { $0.zIndex < $1.zIndex })
273273
return sortedAnnotations
274-
275-
276274
}
277275

278276

lib/src/bitmap.dart

+43-15
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,42 @@
44

55
part of apple_maps_flutter;
66

7-
enum AnnotationColor {
8-
RED,
9-
GREEN,
10-
PURPLE,
11-
}
12-
137
/// Defines a bitmap image. For a annotation, this class can be used to set the
148
/// image of the annotation icon. For a ground overlay, it can be used to set the
159
/// image to place on the surface of the earth.
1610
class BitmapDescriptor {
1711
const BitmapDescriptor._(this._json);
1812

13+
/// Convenience hue value representing red.
14+
static const double hueRed = 0.0;
15+
16+
/// Convenience hue value representing orange.
17+
static const double hueOrange = 30.0;
18+
19+
/// Convenience hue value representing yellow.
20+
static const double hueYellow = 60.0;
21+
22+
/// Convenience hue value representing green.
23+
static const double hueGreen = 120.0;
24+
25+
/// Convenience hue value representing cyan.
26+
static const double hueCyan = 180.0;
27+
28+
/// Convenience hue value representing azure.
29+
static const double hueAzure = 210.0;
30+
31+
/// Convenience hue value representing blue.
32+
static const double hueBlue = 240.0;
33+
34+
/// Convenience hue value representing violet.
35+
static const double hueViolet = 270.0;
36+
37+
/// Convenience hue value representing magenta.
38+
static const double hueMagenta = 300.0;
39+
40+
/// Convenience hue value representing rose.
41+
static const double hueRose = 330.0;
42+
1943
/// Creates a BitmapDescriptor that refers to the default/Pin annotation image.
2044
static const BitmapDescriptor defaultAnnotation =
2145
BitmapDescriptor._(<dynamic>['defaultAnnotation']);
@@ -24,18 +48,22 @@ class BitmapDescriptor {
2448
static const BitmapDescriptor markerAnnotation =
2549
BitmapDescriptor._(<dynamic>['markerAnnotation']);
2650

27-
/// Creates a BitmapDescriptor that refers to a colorization of the marker
28-
/// annotation image. For convenience, there is a predefined set of [AnnotationColors].
29-
/// See e.g. [AnnotationColor.RED].
30-
static BitmapDescriptor markerAnnotationWithColor(AnnotationColor color) {
31-
return BitmapDescriptor._(<dynamic>['markerAnnotation', color.index]);
51+
/// Creates a BitmapDescriptor that refers to a colorization of the default
52+
/// marker image. For convenience, there is a predefined set of hue values.
53+
/// See e.g. [hueYellow].
54+
static BitmapDescriptor markerAnnotationWithHue(double hue) {
55+
assert(0.0 <= hue && hue < 360.0);
56+
double iosCompatibleHue = hue / 360.0;
57+
return BitmapDescriptor._(<dynamic>['markerAnnotation', iosCompatibleHue]);
3258
}
3359

3460
/// Creates a BitmapDescriptor that refers to a colorization of the default/Pin
35-
/// annotation image. For convenience, there is a predefined set of [AnnotationColors].
36-
/// See e.g. [AnnotationColor.RED].
37-
static BitmapDescriptor defaultAnnotationWithColor(AnnotationColor color) {
38-
return BitmapDescriptor._(<dynamic>['defaultAnnotation', color.index]);
61+
/// annotation image. For convenience, there is a predefined set of hue values.
62+
/// See e.g. [hueCyan].
63+
static BitmapDescriptor defaultAnnotationWithHue(double hue) {
64+
assert(0.0 <= hue && hue < 360.0);
65+
double iosCompatibleHue = hue / 360.0;
66+
return BitmapDescriptor._(<dynamic>['defaultAnnotation', iosCompatibleHue]);
3967
}
4068

4169
/// Creates a [BitmapDescriptor] from an asset image.

0 commit comments

Comments
 (0)