diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index 20424d1..2ce4060 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -4352f65289e7fa16502be59af107b44a \ No newline at end of file +15bc9e2f5da4e082f1b5a1ced9ac010e \ No newline at end of file diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 184605f..360d134 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -381,7 +381,7 @@ "$(PROJECT_DIR)/Flutter", ); MARKETING_VERSION = 0.0.4; - PRODUCT_BUNDLE_IDENTIFIER = de.luisthein.appleMapsFlutterExample3; + PRODUCT_BUNDLE_IDENTIFIER = de.luisthein.appleMapsFlutterExample4; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -517,7 +517,7 @@ "$(PROJECT_DIR)/Flutter", ); MARKETING_VERSION = 0.0.4; - PRODUCT_BUNDLE_IDENTIFIER = de.luisthein.appleMapsFlutterExample3; + PRODUCT_BUNDLE_IDENTIFIER = de.luisthein.appleMapsFlutterExample4; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -550,7 +550,7 @@ "$(PROJECT_DIR)/Flutter", ); MARKETING_VERSION = 0.0.4; - PRODUCT_BUNDLE_IDENTIFIER = de.luisthein.appleMapsFlutterExample3; + PRODUCT_BUNDLE_IDENTIFIER = de.luisthein.appleMapsFlutterExample4; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/example/lib/place_annotation.dart b/example/lib/place_annotation.dart index 620f1fa..7e1c8c5 100644 --- a/example/lib/place_annotation.dart +++ b/example/lib/place_annotation.dart @@ -37,6 +37,7 @@ class PlaceAnnotationBodyState extends State { Map annotations = {}; AnnotationId selectedAnnotation; int _annotationIdCounter = 1; + BitmapDescriptor _annotationIcon; void _onMapCreated(AppleMapController controller) { this.controller = controller; @@ -52,8 +53,8 @@ class PlaceAnnotationBodyState extends State { if (tappedAnnotation != null) { setState(() { if (annotations.containsKey(selectedAnnotation)) { - final Annotation resetOld = annotations[selectedAnnotation] - .copyWith(iconParam: BitmapDescriptor.defaultAnnotation); + final Annotation resetOld = + annotations[selectedAnnotation].copyWith(); annotations[selectedAnnotation] = resetOld; } selectedAnnotation = annotationId; @@ -76,12 +77,17 @@ class PlaceAnnotationBodyState extends State { annotationId: annotationId, icon: iconType == 'marker' ? BitmapDescriptor.markerAnnotation - : BitmapDescriptor.defaultAnnotation, + : iconType == 'pin' + ? BitmapDescriptor.defaultAnnotation + : _annotationIcon, position: LatLng( center.latitude + sin(_annotationIdCounter * pi / 6.0) / 20.0, center.longitude + cos(_annotationIdCounter * pi / 6.0) / 20.0, ), - infoWindow: InfoWindow(title: annotationIdVal, snippet: '*'), + infoWindow: InfoWindow( + title: annotationIdVal, + snippet: '*', + onTap: () => print('InfowWindow of id: $annotationId tapped.')), onTap: () { _onAnnotationTapped(annotationId); }, @@ -128,7 +134,8 @@ class PlaceAnnotationBodyState extends State { Future _changeInfo() async { final Annotation annotation = annotations[selectedAnnotation]; - final String newSnippet = annotation.infoWindow.snippet + '*'; + final String newSnippet = annotation.infoWindow.snippet + + (annotation.infoWindow.snippet.length % 10 == 0 ? '\n' : '*'); setState(() { annotations[selectedAnnotation] = annotation.copyWith( infoWindowParam: annotation.infoWindow.copyWith( @@ -157,8 +164,44 @@ class PlaceAnnotationBodyState extends State { }); } + Future _createAnnotationImageFromAsset(BuildContext context) async { + if (_annotationIcon == null) { + final ImageConfiguration imageConfiguration = + createLocalImageConfiguration(context); + BitmapDescriptor.fromAssetImage( + imageConfiguration, 'assets/red_square.png') + .then(_updateBitmap); + } + } + + void _updateBitmap(BitmapDescriptor bitmap) { + setState(() { + _annotationIcon = bitmap; + }); + } + + Future _showInfoWindow() async { + final Annotation annotation = annotations[selectedAnnotation]; + await this.controller.showMarkerInfoWindow(annotation.annotationId); + } + + Future _hideInfoWindow() async { + final Annotation annotation = annotations[selectedAnnotation]; + this.controller.hideMarkerInfoWindow(annotation.annotationId); + } + + Future _isInfoWindowShown() async { + final Annotation annotation = annotations[selectedAnnotation]; + print( + 'Is InfowWindow visible: ${await this.controller.isMarkerInfoWindowShown(annotation.annotationId)}'); + return await this + .controller + .isMarkerInfoWindowShown(annotation.annotationId); + } + @override Widget build(BuildContext context) { + _createAnnotationImageFromAsset(context); return Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.stretch, @@ -194,6 +237,10 @@ class PlaceAnnotationBodyState extends State { child: const Text('add markerAnnotation'), onPressed: () => _add('marker'), ), + FlatButton( + child: const Text('add customAnnotation'), + onPressed: () => _add('customAnnotation'), + ), FlatButton( child: const Text('remove'), onPressed: _remove, @@ -202,6 +249,10 @@ class PlaceAnnotationBodyState extends State { child: const Text('change info'), onPressed: _changeInfo, ), + FlatButton( + child: const Text('infoWindow is shown?s'), + onPressed: _isInfoWindowShown, + ), ], ), Column( @@ -222,6 +273,14 @@ class PlaceAnnotationBodyState extends State { child: const Text('toggle visible'), onPressed: _toggleVisible, ), + FlatButton( + child: const Text('show infoWindow'), + onPressed: _showInfoWindow, + ), + FlatButton( + child: const Text('hide infoWindow'), + onPressed: _hideInfoWindow, + ), ], ), ], diff --git a/example/pubspec.lock b/example/pubspec.lock index 85305dd..6eef81d 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -42,28 +42,28 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.2" + version: "2.5.0-nullsafety.1" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0-nullsafety.1" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.0-nullsafety.3" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.1.3" + version: "1.2.0-nullsafety.1" cli_util: dependency: transitive description: @@ -77,14 +77,14 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.1.0-nullsafety.1" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.14.13" + version: "1.15.0-nullsafety.3" convert: dependency: transitive description: @@ -126,14 +126,14 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0-nullsafety.1" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "5.2.1" + version: "6.0.0-nullsafety.2" flutter: dependency: "direct main" description: flutter @@ -189,13 +189,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.3" - intl: - dependency: transitive - description: - name: intl - url: "https://pub.dartlang.org" - source: hosted - version: "0.16.1" io: dependency: transitive description: @@ -209,14 +202,14 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.1+1" + version: "0.6.3-nullsafety.1" json_rpc_2: dependency: transitive description: name: json_rpc_2 url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "2.2.2" logging: dependency: transitive description: @@ -230,14 +223,14 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.8" + version: "0.12.10-nullsafety.1" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.8" + version: "1.3.0-nullsafety.3" mime: dependency: transitive description: @@ -279,35 +272,35 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0-nullsafety.1" pedantic: dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.9.0" + version: "1.10.0-nullsafety.1" platform: dependency: transitive description: name: platform url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "3.0.0-nullsafety.2" pool: dependency: transitive description: name: pool url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.5.0-nullsafety.1" process: dependency: transitive description: name: process url: "https://pub.dartlang.org" source: hosted - version: "3.0.13" + version: "4.0.0-nullsafety.2" pub_semver: dependency: transitive description: @@ -354,42 +347,42 @@ packages: name: source_map_stack_trace url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0-nullsafety.2" source_maps: dependency: transitive description: name: source_maps url: "https://pub.dartlang.org" source: hosted - version: "0.10.9" + version: "0.10.10-nullsafety.1" source_span: dependency: transitive description: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0-nullsafety.2" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.9.5" + version: "1.10.0-nullsafety.1" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0-nullsafety.1" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.1.0-nullsafety.1" sync_http: dependency: transitive description: @@ -403,42 +396,42 @@ packages: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0-nullsafety.1" test: dependency: "direct dev" description: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.15.2" + version: "1.16.0-nullsafety.5" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.17" + version: "0.2.19-nullsafety.2" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.3.10" + version: "0.3.12-nullsafety.5" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0-nullsafety.3" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.1.0-nullsafety.3" vm_service: dependency: transitive description: @@ -489,5 +482,5 @@ packages: source: hosted version: "2.2.0" sdks: - dart: ">=2.9.0-14.0.dev <3.0.0" + dart: ">=2.10.0-110 <2.11.0" flutter: ">=1.10.0 <2.0.0" diff --git a/ios/Classes/Annotations/AnnotationController.swift b/ios/Classes/Annotations/AnnotationController.swift index e4d7988..aa9c537 100644 --- a/ios/Classes/Annotations/AnnotationController.swift +++ b/ios/Classes/Annotations/AnnotationController.swift @@ -9,37 +9,34 @@ import Foundation import MapKit class AnnotationController: NSObject { - + let mapView: MKMapView let channel: FlutterMethodChannel let registrar: FlutterPluginRegistrar - + public init(mapView :MKMapView, channel :FlutterMethodChannel, registrar: FlutterPluginRegistrar) { self.mapView = mapView self.channel = channel self.registrar = registrar } - + func getAnnotationView(annotation: FlutterAnnotation) -> MKAnnotationView{ let identifier :String = annotation.id var annotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: identifier) let oldflutterAnnoation = annotationView?.annotation as? FlutterAnnotation if annotationView == nil || oldflutterAnnoation?.icon.iconType != annotation.icon.iconType { if annotation.icon.iconType == IconType.PIN { - annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier) + annotationView = getPinAnnotationView(annotation: annotation, id: identifier) } else if annotation.icon.iconType == IconType.MARKER { - if #available(iOS 11.0, *) { - annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier) - } else { - annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier) - } + annotationView = getMarkerAnnotationView(annotation: annotation, id: identifier) } else if annotation.icon.iconType == IconType.CUSTOM { - annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier) - annotationView!.image = annotation.icon.image + annotationView = getCustomAnnotationView(annotation: annotation, id: identifier) } - } else { - annotationView!.annotation = annotation } + guard annotationView != nil else { + return MKAnnotationView() + } + annotationView!.annotation = annotation // If annotation is not visible set alpha to 0 and don't let the user interact with it if !annotation.isVisible! { annotationView!.canShowCallout = false @@ -47,20 +44,22 @@ class AnnotationController: NSObject { annotationView!.isDraggable = false return annotationView! } + if annotation.icon.iconType == .CUSTOM || annotation.icon.iconType == .PIN { + initInfoWindow(annotation: annotation, annotationView: annotationView!) + } annotationView!.canShowCallout = true annotationView!.alpha = CGFloat(annotation.alpha ?? 1.00) annotationView!.isDraggable = annotation.isDraggable ?? false return annotationView! } - + public func annotationsToAdd(annotations :NSArray) { for annotation in annotations { let annotationData :Dictionary = annotation as! Dictionary addAnnotation(annotationData: annotationData) } } - - + public func annotationsToChange(annotations: NSArray) { let oldAnnotations :[MKAnnotation] = mapView.annotations for annotation in annotations { @@ -75,14 +74,13 @@ class AnnotationController: NSObject { } else { oldFlutterAnnotation.wasDragged = false } - } + } } } } } } - - + public func annotationsIdsToRemove(annotationIds: NSArray) { for annotationId in annotationIds { if let _annotationId :String = annotationId as? String { @@ -90,35 +88,102 @@ class AnnotationController: NSObject { } } } - - + public func onAnnotationClick(annotation :MKAnnotation) { if let flutterAnnotation :FlutterAnnotation = annotation as? FlutterAnnotation { flutterAnnotation.wasDragged = true channel.invokeMethod("annotation#onTap", arguments: ["annotationId" : flutterAnnotation.id]) } } - - + private func removeAnnotation(id: String) { - for annotation in mapView.annotations { - if let flutterAnnotation :FlutterAnnotation = annotation as? FlutterAnnotation { - if flutterAnnotation.id == id { - mapView.removeAnnotation(flutterAnnotation) - } - } + if let flutterAnnotation :FlutterAnnotation = self.getAnnotation(with: id) { + mapView.removeAnnotation(flutterAnnotation) } } - - + private func updateAnnotationOnMap(oldAnnotation: FlutterAnnotation, newAnnotation :FlutterAnnotation) { removeAnnotation(id: oldAnnotation.id) mapView.addAnnotation(newAnnotation) } - - + + private func initInfoWindow(annotation: FlutterAnnotation, annotationView: MKAnnotationView) { + if annotation.infoWindowConsumesTapEvents { + annotationView.rightCalloutAccessoryView = UIButton(type: .detailDisclosure) + } + if #available(iOS 9.0, *) { + let lines = annotation.subtitle?.split(whereSeparator: \.isNewline) + if lines != nil { + let customCallout = UIStackView() + customCallout.axis = .vertical + customCallout.alignment = .fill + customCallout.distribution = .fill + for line in lines! { + let subtitle = UILabel() + subtitle.text = String(line) + customCallout.addArrangedSubview(subtitle) + } + annotationView.detailCalloutAccessoryView = customCallout + } + } + } + + public func showAnnotation(with id: String) { + let annotation = self.getAnnotation(with: id) + guard annotation != nil else { + return + } + self.mapView.selectAnnotation(annotation!, animated: true) + } + + public func hideAnnotation(with id: String) { + let annotation = self.getAnnotation(with: id) + guard annotation != nil else { + return + } + self.mapView.deselectAnnotation(annotation!, animated: true) + } + + public func isAnnotationSelected(with id: String) -> Bool { + return self.mapView.selectedAnnotations.contains(where: { annotation in return self.getAnnotation(with: id) == (annotation as? FlutterAnnotation)}) + } + + 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 addAnnotation(annotationData: Dictionary) { let annotation :MKAnnotation = FlutterAnnotation(fromDictionary: annotationData, registrar: registrar) mapView.addAnnotation(annotation) } + + private func getPinAnnotationView(annotation: MKAnnotation, id: String) -> MKPinAnnotationView { + if #available(iOS 11.0, *) { + self.mapView.register(MKPinAnnotationView.self, forAnnotationViewWithReuseIdentifier: id) + return self.mapView.dequeueReusableAnnotationView(withIdentifier: id, for: annotation) as! MKPinAnnotationView + } else { + return MKPinAnnotationView.init(annotation: annotation, reuseIdentifier: id) + } + } + + private func getMarkerAnnotationView(annotation: MKAnnotation, id: String) -> MKAnnotationView { + if #available(iOS 11.0, *) { + self.mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: id) + return self.mapView.dequeueReusableAnnotationView(withIdentifier: id, for: annotation) + } else { + return MKPinAnnotationView.init(annotation: annotation, reuseIdentifier: id) + } + } + + private func getCustomAnnotationView(annotation: FlutterAnnotation, id: String) -> MKAnnotationView { + let annotationView: MKAnnotationView? + if #available(iOS 11.0, *) { + self.mapView.register(MKAnnotationView.self, forAnnotationViewWithReuseIdentifier: id) + annotationView = self.mapView.dequeueReusableAnnotationView(withIdentifier: id, for: annotation) + } else { + annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: id) + } + annotationView?.image = annotation.icon.image + return annotationView! + } } diff --git a/ios/Classes/Annotations/FlutterAnnotation.swift b/ios/Classes/Annotations/FlutterAnnotation.swift index d0779ba..80f264c 100644 --- a/ios/Classes/Annotations/FlutterAnnotation.swift +++ b/ios/Classes/Annotations/FlutterAnnotation.swift @@ -13,6 +13,7 @@ class FlutterAnnotation: NSObject, MKAnnotation { var id :String! var title: String? var subtitle: String? + var infoWindowConsumesTapEvents: Bool = false var image: UIImage? var alpha: Double? var isDraggable: Bool? @@ -28,6 +29,7 @@ class FlutterAnnotation: NSObject, MKAnnotation { self.coordinate = CLLocationCoordinate2D(latitude: lat, longitude: long) self.title = infoWindow["title"] as? String self.subtitle = infoWindow["snippet"] as? String + self.infoWindowConsumesTapEvents = infoWindow["consumesTapEvents"] as? Bool ?? false self.id = annotationData["annotationId"] as? String self.isVisible = annotationData["visible"] as? Bool self.isDraggable = annotationData["draggable"] as? Bool diff --git a/ios/Classes/MapView/AppleMapController.swift b/ios/Classes/MapView/AppleMapController.swift index 77a3775..d08889f 100644 --- a/ios/Classes/MapView/AppleMapController.swift +++ b/ios/Classes/MapView/AppleMapController.swift @@ -74,11 +74,16 @@ public class AppleMapController : NSObject, FlutterPlatformView, MKMapViewDelega } } - public func view() -> UIView { return mapView } + public func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) { + if let flutterAnnotation: FlutterAnnotation = view.annotation as? FlutterAnnotation { + self.channel.invokeMethod("infoWindow#onTap", arguments: ["annotationId": flutterAnnotation.id]) + } + } + // onIdle public func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) { self.channel.invokeMethod("camera#onIdle", arguments: "") @@ -121,15 +126,27 @@ public class AppleMapController : NSObject, FlutterPlatformView, MKMapViewDelega switch(call.method) { case "annotations#update": if let annotationsToAdd = args["annotationsToAdd"] as? NSArray { - self.annotationController.annotationsToAdd(annotations: annotationsToAdd) + if annotationsToAdd.count > 0 { + self.annotationController.annotationsToAdd(annotations: annotationsToAdd) + } } if let annotationsToChange = args["annotationsToChange"] as? NSArray { - self.annotationController.annotationsToChange(annotations: annotationsToChange) + if annotationsToChange.count > 0 { + self.annotationController.annotationsToChange(annotations: annotationsToChange) + } } if let annotationsToDelete = args["annotationIdsToRemove"] as? NSArray { - self.annotationController.annotationsIdsToRemove(annotationIds: annotationsToDelete) + if annotationsToDelete.count > 0 { + self.annotationController.annotationsIdsToRemove(annotationIds: annotationsToDelete) + } } result(nil) + case "annotations#showInfoWindow": + self.annotationController.showAnnotation(with: args["annotationId"] as! String) + case "annotations#hideInfoWindow": + self.annotationController.hideAnnotation(with: args["annotationId"] as! String) + case "annotations#isInfoWindowShown": + result(self.annotationController.isAnnotationSelected(with: args["annotationId"] as! String)) case "polylines#update": if let polylinesToAdd: NSArray = args["polylinesToAdd"] as? NSArray { self.polylineController.addPolylines(polylineData: polylinesToAdd) diff --git a/lib/src/annotation.dart b/lib/src/annotation.dart index 6a6750b..6285666 100644 --- a/lib/src/annotation.dart +++ b/lib/src/annotation.dart @@ -72,6 +72,7 @@ class InfoWindow { addIfPresent('title', title); addIfPresent('snippet', snippet); addIfPresent('anchor', _offsetToJson(anchor)); + addIfPresent('consumesTapEvents', onTap != null); return json; } @@ -83,7 +84,8 @@ class InfoWindow { final InfoWindow typedOther = other; return title == typedOther.title && snippet == typedOther.snippet && - anchor == typedOther.anchor; + anchor == typedOther.anchor && + onTap == typedOther.onTap; } @override @@ -91,7 +93,7 @@ class InfoWindow { @override String toString() { - return 'InfoWindow{title: $title, snippet: $snippet, anchor: $anchor}'; + return 'InfoWindow{title: $title, snippet: $snippet, anchor: $anchor, consumesTapEvents: ${onTap != null}}'; } } diff --git a/lib/src/apple_map.dart b/lib/src/apple_map.dart index ca62ba9..5f483f6 100644 --- a/lib/src/apple_map.dart +++ b/lib/src/apple_map.dart @@ -237,6 +237,9 @@ class _AppleMapState extends State { controller._updateAnnotations(_AnnotationUpdates.from( _annotations.values.toSet(), widget.annotations)); _annotations = _keyByAnnotationId(widget.annotations); + _annotations.forEach((key, value) { + print('Id: ${key.value} icon = ${value.icon._toJson()}'); + }); } void _updatePolylines() async { diff --git a/lib/src/controller.dart b/lib/src/controller.dart index edc5b68..fcb2641 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -167,6 +167,48 @@ class AppleMapController { }); } + /// Programmatically show the Info Window for a [Marker]. + /// + /// The `markerId` must match one of the markers on the map. + /// An invalid `markerId` triggers an "Invalid markerId" error. + /// + /// * See also: + /// * [hideMarkerInfoWindow] to hide the Info Window. + /// * [isMarkerInfoWindowShown] to check if the Info Window is showing. + Future showMarkerInfoWindow(AnnotationId annotationId) { + assert(annotationId != null); + return channel.invokeMethod('annotations#showInfoWindow', + {'annotationId': annotationId.value}); + } + + /// Programmatically hide the Info Window for a [Marker]. + /// + /// The `markerId` must match one of the markers on the map. + /// An invalid `markerId` triggers an "Invalid markerId" error. + /// + /// * See also: + /// * [showMarkerInfoWindow] to show the Info Window. + /// * [isMarkerInfoWindowShown] to check if the Info Window is showing. + Future hideMarkerInfoWindow(AnnotationId annotationId) { + assert(annotationId != null); + return channel.invokeMethod('annotations#hideInfoWindow', + {'annotationId': annotationId.value}); + } + + /// Returns `true` when the [InfoWindow] is showing, `false` otherwise. + /// + /// The `markerId` must match one of the markers on the map. + /// An invalid `markerId` triggers an "Invalid markerId" error. + /// + /// * See also: + /// * [showMarkerInfoWindow] to show the Info Window. + /// * [hideMarkerInfoWindow] to hide the Info Window. + Future isMarkerInfoWindowShown(AnnotationId annotationId) { + assert(annotationId != null); + return channel.invokeMethod('annotations#isInfoWindowShown', + {'annotationId': annotationId.value}); + } + /// Changes the map camera position. /// /// The returned [Future] completes after the change has been made on the