Skip to content

Commit

Permalink
fix: Marker and Annotation colors
Browse files Browse the repository at this point in the history
It is now possible to provide a hue value to change the marker or
pin annotation color.

fixes #38
  • Loading branch information
LuisThein committed Jul 30, 2022
1 parent 866ff78 commit 473a546
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 41 deletions.
2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c

COCOAPODS: 1.10.0
COCOAPODS: 1.11.3
2 changes: 2 additions & 0 deletions example/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,7 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
</dict>
</plist>
40 changes: 32 additions & 8 deletions example/lib/place_annotation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,31 @@ class PlaceAnnotationBodyState extends State<PlaceAnnotationBody> {
_annotationIdCounter++;
final AnnotationId annotationId = AnnotationId(annotationIdVal);

var bitMapDescriptor;

switch (iconType) {
case 'marker':
bitMapDescriptor = BitmapDescriptor.markerAnnotation;
break;
case 'pin':
bitMapDescriptor = BitmapDescriptor.defaultAnnotation;
break;
case 'customAnnotationFromBytes':
bitMapDescriptor = _iconFromBytes;
break;
case 'markerAnnotationWithHue':
bitMapDescriptor = BitmapDescriptor.markerAnnotationWithHue(
new Random().nextDouble() * 360);
break;
case 'defaultAnnotationWithColor':
bitMapDescriptor = BitmapDescriptor.defaultAnnotationWithHue(
new Random().nextDouble() * 360);
break;
}

final Annotation annotation = Annotation(
annotationId: annotationId,
icon: iconType == 'marker'
? BitmapDescriptor.markerAnnotation
: iconType == 'pin'
? BitmapDescriptor.defaultAnnotation
: iconType == 'customAnnotationFromBytes'
? _iconFromBytes
: _annotationIcon!,
icon: bitMapDescriptor,
position: LatLng(
center.latitude + sin(_annotationIdCounter * pi / 6.0) / 20.0,
center.longitude + cos(_annotationIdCounter * pi / 6.0) / 20.0,
Expand All @@ -97,7 +113,7 @@ class PlaceAnnotationBodyState extends State<PlaceAnnotationBody> {
title: annotationIdVal,
anchor: Offset(0.5, 0.0),
snippet: '*',
onTap: () => print('InfowWindow of id: $annotationId tapped.')),
onTap: () => print('InfoWindow with id: $annotationId tapped.')),
onTap: () {
_onAnnotationTapped(annotationId);
},
Expand Down Expand Up @@ -257,10 +273,18 @@ class PlaceAnnotationBodyState extends State<PlaceAnnotationBody> {
child: const Text('add defaultAnnotation'),
onPressed: () => _add('pin'),
),
TextButton(
child: const Text('add defaultWithHue'),
onPressed: () => _add('defaultAnnotationWithColor'),
),
TextButton(
child: const Text('add markerAnnotation'),
onPressed: () => _add('marker'),
),
TextButton(
child: const Text('add markerWithHue'),
onPressed: () => _add('markerAnnotationWithHue'),
),
TextButton(
child: const Text('add customAnnotation'),
onPressed: () => _add('customAnnotation'),
Expand Down
29 changes: 19 additions & 10 deletions ios/Classes/Annotations/AnnotationController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ extension AppleMapController: AnnotationDelegate {
} else {
annotation.selectedProgrammatically = false
}

if annotation.infoWindowConsumesTapEvents {
let tapGestureRecognizer = InfoWindowTapGestureRecognizer(target: self, action: #selector(onCalloutTapped))
tapGestureRecognizer.annotationId = annotation.id
Expand All @@ -30,7 +30,7 @@ extension AppleMapController: AnnotationDelegate {
}
}
}

public func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
Expand All @@ -39,7 +39,7 @@ extension AppleMapController: AnnotationDelegate {
}
return nil
}

func getAnnotationView(annotation: FlutterAnnotation) -> MKAnnotationView {
let identifier: String = annotation.id
var annotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
Expand Down Expand Up @@ -166,7 +166,7 @@ extension AppleMapController: AnnotationDelegate {
}
}
}

@objc func onCalloutTapped(infoWindowTap: InfoWindowTapGestureRecognizer) {
if infoWindowTap.annotationId != nil && self.currentlySelectedAnnotation == infoWindowTap.annotationId! {
self.channel.invokeMethod("infoWindow#onTap", arguments: ["annotationId": infoWindowTap.annotationId])
Expand All @@ -179,7 +179,7 @@ extension AppleMapController: AnnotationDelegate {
private func getAnnotation(with id: String) -> FlutterAnnotation? {
return self.mapView.annotations.filter { annotation in return (annotation as? FlutterAnnotation)?.id == id }.first as? FlutterAnnotation
}

private func annotationExists(with id: String) -> Bool {
return self.getAnnotation(with: id) != nil
}
Expand All @@ -188,7 +188,7 @@ extension AppleMapController: AnnotationDelegate {
let annotation: FlutterAnnotation = FlutterAnnotation(fromDictionary: annotationData, registrar: registrar)
self.addAnnotation(annotation: annotation)
}

/**
Checks if an Annotation with the same id exists and removes it before adding if necessary
- Parameter annotation: the FlutterAnnotation that should be added
Expand All @@ -203,15 +203,15 @@ extension AppleMapController: AnnotationDelegate {
}
self.mapView.addAnnotation(annotation)
}

private func getNextAnnotationZIndex() -> Double {
let mapViewAnnotations = self.mapView.getMapViewAnnotations()
if mapViewAnnotations.isEmpty {
return 0;
}
return (mapViewAnnotations.last??.zIndex ?? 0) + 1
}

private func isAnnoationInFront(zIndex: Double) -> Bool {
return (self.mapView.getMapViewAnnotations().last??.zIndex ?? 0) == zIndex
}
Expand All @@ -224,8 +224,12 @@ extension AppleMapController: AnnotationDelegate {
} else {
pinAnnotationView = MKPinAnnotationView.init(annotation: annotation, reuseIdentifier: id)
}

pinAnnotationView.layer.zPosition = annotation.zIndex

if let hueColor: Double = annotation.icon.hueColor {
pinAnnotationView.pinTintColor = UIColor.init(hue: hueColor, saturation: 1, brightness: 1, alpha: 1)
}

return pinAnnotationView
}

Expand All @@ -234,6 +238,11 @@ extension AppleMapController: AnnotationDelegate {
self.mapView.register(FlutterMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: id)
let markerAnnotationView: FlutterMarkerAnnotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: id, for: annotation) as! FlutterMarkerAnnotationView
markerAnnotationView.stickyZPosition = annotation.zIndex

if let hueColor: Double = annotation.icon.hueColor {
markerAnnotationView.markerTintColor = UIColor.init(hue: hueColor, saturation: 1, brightness: 1, alpha: 1)
}

return markerAnnotationView
}

Expand All @@ -260,7 +269,7 @@ extension AppleMapController: AnnotationDelegate {
private func getInfoWindowYOffset(annotationView: MKAnnotationView, annotation: FlutterAnnotation) -> CGFloat {
return annotationView.frame.height * CGFloat(annotation.calloutOffset.y)
}

private func moveToFront(annotation: FlutterAnnotation) {
let id: String = annotation.id
annotation.zIndex = self.getNextAnnotationZIndex()
Expand Down
9 changes: 8 additions & 1 deletion ios/Classes/Annotations/AnnotationIcon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,20 @@ class AnnotationIcon: Equatable {
var iconType: IconType
var id: String
var image: UIImage?
var hueColor: Double?

public init(id: String, iconType: IconType) {
self.iconType = iconType
self.id = id
}

public init(named name: String, id: String, iconScale: CGFloat? = 1.0) {
public init(id: String, iconType: IconType, hueColor: Double) {
self.iconType = iconType
self.id = id
self.hueColor = hueColor
}

public init(withAsset name: String, id: String, iconScale: CGFloat? = 1.0) {
self.iconType = .CUSTOM_FROM_ASSET
self.id = id
if let uiImage: UIImage = UIImage.init(named: name) {
Expand Down
9 changes: 5 additions & 4 deletions ios/Classes/Annotations/FlutterAnnotation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,19 @@ class FlutterAnnotation: NSObject, MKAnnotation {

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

if iconType == .CUSTOM_FROM_ASSET {
let assetPath: String = iconData[1] as! String
scaleParam = CGFloat(iconData[2] as? Double ?? 1.0)
icon = AnnotationIcon(named: registrar.lookupKey(forAsset: assetPath), id: annotationId, iconScale: scaleParam)
icon = AnnotationIcon(withAsset: registrar.lookupKey(forAsset: assetPath), id: annotationId, iconScale: scaleParam)
} else if iconType == .CUSTOM_FROM_BYTES {
icon = AnnotationIcon(fromBytes: iconData[1] as! FlutterStandardTypedData, id: annotationId)
}else {
icon = AnnotationIcon(id: annotationId, iconType: iconType)
} else if iconData.count > 1 {
icon = AnnotationIcon(id: annotationId, iconType: iconType, hueColor: iconData[1] as! Double)

}
return icon
}
Expand Down
2 changes: 0 additions & 2 deletions ios/Classes/MapView/FlutterMapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,6 @@ class FlutterMapView: MKMapView, UIGestureRecognizerDelegate {
let flutterAnnotations = self.annotations as? [FlutterAnnotation] ?? []
let sortedAnnotations = flutterAnnotations.sorted(by: { $0.zIndex < $1.zIndex })
return sortedAnnotations


}


Expand Down
58 changes: 43 additions & 15 deletions lib/src/bitmap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,42 @@

part of apple_maps_flutter;

enum AnnotationColor {
RED,
GREEN,
PURPLE,
}

/// Defines a bitmap image. For a annotation, this class can be used to set the
/// image of the annotation icon. For a ground overlay, it can be used to set the
/// image to place on the surface of the earth.
class BitmapDescriptor {
const BitmapDescriptor._(this._json);

/// Convenience hue value representing red.
static const double hueRed = 0.0;

/// Convenience hue value representing orange.
static const double hueOrange = 30.0;

/// Convenience hue value representing yellow.
static const double hueYellow = 60.0;

/// Convenience hue value representing green.
static const double hueGreen = 120.0;

/// Convenience hue value representing cyan.
static const double hueCyan = 180.0;

/// Convenience hue value representing azure.
static const double hueAzure = 210.0;

/// Convenience hue value representing blue.
static const double hueBlue = 240.0;

/// Convenience hue value representing violet.
static const double hueViolet = 270.0;

/// Convenience hue value representing magenta.
static const double hueMagenta = 300.0;

/// Convenience hue value representing rose.
static const double hueRose = 330.0;

/// Creates a BitmapDescriptor that refers to the default/Pin annotation image.
static const BitmapDescriptor defaultAnnotation =
BitmapDescriptor._(<dynamic>['defaultAnnotation']);
Expand All @@ -24,18 +48,22 @@ class BitmapDescriptor {
static const BitmapDescriptor markerAnnotation =
BitmapDescriptor._(<dynamic>['markerAnnotation']);

/// Creates a BitmapDescriptor that refers to a colorization of the marker
/// annotation image. For convenience, there is a predefined set of [AnnotationColors].
/// See e.g. [AnnotationColor.RED].
static BitmapDescriptor markerAnnotationWithColor(AnnotationColor color) {
return BitmapDescriptor._(<dynamic>['markerAnnotation', color.index]);
/// Creates a BitmapDescriptor that refers to a colorization of the default
/// marker image. For convenience, there is a predefined set of hue values.
/// See e.g. [hueYellow].
static BitmapDescriptor markerAnnotationWithHue(double hue) {
assert(0.0 <= hue && hue < 360.0);
double iosCompatibleHue = hue / 360.0;
return BitmapDescriptor._(<dynamic>['markerAnnotation', iosCompatibleHue]);
}

/// Creates a BitmapDescriptor that refers to a colorization of the default/Pin
/// annotation image. For convenience, there is a predefined set of [AnnotationColors].
/// See e.g. [AnnotationColor.RED].
static BitmapDescriptor defaultAnnotationWithColor(AnnotationColor color) {
return BitmapDescriptor._(<dynamic>['defaultAnnotation', color.index]);
/// annotation image. For convenience, there is a predefined set of hue values.
/// See e.g. [hueCyan].
static BitmapDescriptor defaultAnnotationWithHue(double hue) {
assert(0.0 <= hue && hue < 360.0);
double iosCompatibleHue = hue / 360.0;
return BitmapDescriptor._(<dynamic>['defaultAnnotation', iosCompatibleHue]);
}

/// Creates a [BitmapDescriptor] from an asset image.
Expand Down

0 comments on commit 473a546

Please sign in to comment.