GoogleMaps on iOS (#525)
diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index 968bccc..0ee9d40 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java
@@ -37,10 +37,6 @@ return BitmapDescriptorFactory.fromAsset( FlutterMain.getLookupKeyForAsset(toString(data.get(1)), toString(data.get(2)))); } - case "fromFile": - return BitmapDescriptorFactory.fromFile(toString(data.get(1))); - case "fromPath": - return BitmapDescriptorFactory.fromPath(toString(data.get(1))); } throw new IllegalArgumentException("Cannot interpret " + o + " as BitmapDescriptor"); } @@ -59,7 +55,7 @@ return builder.build(); } - static CameraUpdate toCameraUpdate(Object o) { + static CameraUpdate toCameraUpdate(Object o, float density) { final List<?> data = toList(o); switch (toString(data.get(0))) { case "newCameraPosition": @@ -67,16 +63,19 @@ case "newLatLng": return CameraUpdateFactory.newLatLng(toLatLng(data.get(1))); case "newLatLngBounds": - return CameraUpdateFactory.newLatLngBounds(toLatLngBounds(data.get(1)), toInt(data.get(2))); + return CameraUpdateFactory.newLatLngBounds( + toLatLngBounds(data.get(1)), toPixels(data.get(2), density)); case "newLatLngZoom": return CameraUpdateFactory.newLatLngZoom(toLatLng(data.get(1)), toFloat(data.get(2))); case "scrollBy": - return CameraUpdateFactory.scrollBy(toFloat(data.get(1)), toFloat(data.get(2))); + return CameraUpdateFactory.scrollBy( // + toFractionalPixels(data.get(1), density), // + toFractionalPixels(data.get(2), density)); case "zoomBy": if (data.size() == 2) { return CameraUpdateFactory.zoomBy(toFloat(data.get(1))); } else { - return CameraUpdateFactory.zoomBy(toFloat(data.get(1)), toPoint(data.get(2))); + return CameraUpdateFactory.zoomBy(toFloat(data.get(1)), toPoint(data.get(2), density)); } case "zoomIn": return CameraUpdateFactory.zoomIn(); @@ -142,9 +141,17 @@ return (Map<?, ?>) o; } - private static Point toPoint(Object o) { + private static float toFractionalPixels(Object o, float density) { + return toFloat(o) * density; + } + + static int toPixels(Object o, float density) { + return (int) toFractionalPixels(o, density); + } + + private static Point toPoint(Object o, float density) { final List<?> data = toList(o); - return new Point(toInt(data.get(0)), toInt(data.get(1))); + return new Point(toPixels(data.get(0), density), toPixels(data.get(1), density)); } private static String toString(Object o) { @@ -157,15 +164,15 @@ if (cameraPosition != null) { sink.setCameraPosition(toCameraPosition(cameraPosition)); } + final Object cameraTargetBounds = data.get("cameraTargetBounds"); + if (cameraTargetBounds != null) { + final List<?> targetData = toList(cameraTargetBounds); + sink.setCameraTargetBounds(toLatLngBounds(targetData.get(0))); + } final Object compassEnabled = data.get("compassEnabled"); if (compassEnabled != null) { sink.setCompassEnabled(toBoolean(compassEnabled)); } - final Object latLngCameraTargetBounds = data.get("latLngCameraTargetBounds"); - if (latLngCameraTargetBounds != null) { - final List<?> targetData = toList(latLngCameraTargetBounds); - sink.setLatLngBoundsForCameraTarget(toLatLngBounds(targetData.get(0))); - } final Object mapType = data.get("mapType"); if (mapType != null) { sink.setMapType(toInt(mapType)); @@ -212,7 +219,7 @@ } final Object consumesTapEvents = data.get("consumesTapEvents"); if (consumesTapEvents != null) { - sink.setConsumesTapEvents(toBoolean(consumesTapEvents)); + sink.setConsumeTapEvents(toBoolean(consumesTapEvents)); } final Object draggable = data.get("draggable"); if (draggable != null) { @@ -231,10 +238,6 @@ final List<?> anchorData = toList(infoWindowAnchor); sink.setInfoWindowAnchor(toFloat(anchorData.get(0)), toFloat(anchorData.get(1))); } - final Object infoWindowShown = data.get("infoWindowShown"); - if (infoWindowShown != null) { - sink.setInfoWindowShown(toBoolean(infoWindowShown)); - } final Object infoWindowText = data.get("infoWindowText"); if (infoWindowText != null) { final List<?> textData = toList(infoWindowText);
diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java index 8920838..f6fe4ef 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java
@@ -39,7 +39,7 @@ } @Override - public void setLatLngBoundsForCameraTarget(LatLngBounds bounds) { + public void setCameraTargetBounds(LatLngBounds bounds) { options.latLngBoundsForCameraTarget(bounds); }
diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index 935e9a5..13a1862 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java
@@ -216,7 +216,8 @@ @Override public void onCameraMoveStarted(int reason) { - onCameraMoveListener.onCameraMoveStarted(reason); + onCameraMoveListener.onCameraMoveStarted( + reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE); cancelSnapshotTimerTasks(); } @@ -348,6 +349,11 @@ } @Override + public void setCameraTargetBounds(LatLngBounds bounds) { + googleMap.setLatLngBoundsForCameraTarget(bounds); + } + + @Override public void setCompassEnabled(boolean compassEnabled) { googleMap.getUiSettings().setCompassEnabled(compassEnabled); } @@ -358,11 +364,6 @@ } @Override - public void setLatLngBoundsForCameraTarget(LatLngBounds bounds) { - googleMap.setLatLngBoundsForCameraTarget(bounds); - } - - @Override public void setTrackCameraPosition(boolean trackCameraPosition) { this.trackCameraPosition = trackCameraPosition; }
diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java index 74b412c..80607de 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java
@@ -11,13 +11,13 @@ interface GoogleMapOptionsSink { void setCameraPosition(CameraPosition position); - void setLatLngBoundsForCameraTarget(LatLngBounds bounds); + void setCameraTargetBounds(LatLngBounds bounds); void setCompassEnabled(boolean compassEnabled); void setMapType(int mapType); - void setTrackCameraPosition(boolean reportCameraMoveEvents); + void setMinMaxZoomPreference(Float min, Float max); void setRotateGesturesEnabled(boolean rotateGesturesEnabled); @@ -25,7 +25,7 @@ void setTiltGesturesEnabled(boolean tiltGesturesEnabled); - void setMinMaxZoomPreference(Float min, Float max); + void setTrackCameraPosition(boolean trackCameraPosition); void setZoomGesturesEnabled(boolean zoomGesturesEnabled); }
diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java index 3b54a2e..692a820 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java
@@ -36,6 +36,7 @@ private final Map<Long, GoogleMapController> googleMaps = new HashMap<>(); private final Registrar registrar; private final MethodChannel channel; + private final float density; private final AtomicInteger state = new AtomicInteger(0); public static void registerWith(Registrar registrar) { @@ -49,6 +50,7 @@ private GoogleMapsPlugin(Registrar registrar, MethodChannel channel) { this.registrar = registrar; this.channel = channel; + this.density = registrar.context().getResources().getDisplayMetrics().density; } @Override @@ -65,8 +67,8 @@ } case "createMap": { - final int width = Convert.toInt(call.argument("width")); - final int height = Convert.toInt(call.argument("height")); + final int width = Convert.toPixels(call.argument("width"), density); + final int height = Convert.toPixels(call.argument("height"), density); final Map<?, ?> options = Convert.toMap(call.argument("options")); final GoogleMapBuilder builder = new GoogleMapBuilder(); Convert.interpretGoogleMapOptions(options, builder); @@ -76,10 +78,10 @@ controller.setOnCameraMoveListener( new OnCameraMoveListener() { @Override - public void onCameraMoveStarted(int reason) { + public void onCameraMoveStarted(boolean isGesture) { final Map<String, Object> arguments = new HashMap<>(2); arguments.put("map", controller.id()); - arguments.put("reason", reason); + arguments.put("isGesture", isGesture); channel.invokeMethod("map#onCameraMoveStarted", arguments); } @@ -107,10 +109,11 @@ channel.invokeMethod("marker#onTap", arguments); } }); - // result.success is called from controller when the GoogleMaps instance is ready + // result.success is called from controller when the GoogleMaps instance + // is ready break; } - case "setMapOptions": + case "updateMapOptions": { final GoogleMapController controller = mapsController(call); Convert.interpretGoogleMapOptions(call.argument("options"), controller); @@ -120,7 +123,8 @@ case "moveCamera": { final GoogleMapController controller = mapsController(call); - final CameraUpdate cameraUpdate = Convert.toCameraUpdate(call.argument("cameraUpdate")); + final CameraUpdate cameraUpdate = + Convert.toCameraUpdate(call.argument("cameraUpdate"), density); controller.moveCamera(cameraUpdate); result.success(null); break; @@ -128,7 +132,8 @@ case "animateCamera": { final GoogleMapController controller = mapsController(call); - final CameraUpdate cameraUpdate = Convert.toCameraUpdate(call.argument("cameraUpdate")); + final CameraUpdate cameraUpdate = + Convert.toCameraUpdate(call.argument("cameraUpdate"), density); controller.animateCamera(cameraUpdate); result.success(null); break; @@ -162,8 +167,8 @@ case "showMapOverlay": { final GoogleMapController controller = mapsController(call); - final int x = Convert.toInt(call.argument("x")); - final int y = Convert.toInt(call.argument("y")); + final int x = Convert.toPixels(call.argument("x"), density); + final int y = Convert.toPixels(call.argument("y"), density); controller.showOverlay(x, y); result.success(null); break;
diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerBuilder.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerBuilder.java index 11e7b5b..532b078 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerBuilder.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerBuilder.java
@@ -13,7 +13,6 @@ private final GoogleMapController mapController; private final MarkerOptions markerOptions; private boolean consumesTapEvents; - private boolean infoWindowShown; MarkerBuilder(GoogleMapController mapController) { this.mapController = mapController; @@ -22,9 +21,6 @@ String build() { final Marker marker = mapController.addMarker(markerOptions, consumesTapEvents); - if (infoWindowShown) { - marker.showInfoWindow(); - } return marker.getId(); } @@ -39,7 +35,7 @@ } @Override - public void setConsumesTapEvents(boolean consumesTapEvents) { + public void setConsumeTapEvents(boolean consumesTapEvents) { this.consumesTapEvents = consumesTapEvents; } @@ -64,11 +60,6 @@ } @Override - public void setInfoWindowShown(boolean infoWindowShown) { - this.infoWindowShown = infoWindowShown; - } - - @Override public void setInfoWindowText(String title, String snippet) { markerOptions.title(title); markerOptions.snippet(snippet);
diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerController.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerController.java index d861a64..73e81f6 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerController.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerController.java
@@ -12,12 +12,12 @@ class MarkerController implements MarkerOptionsSink { private final Marker marker; private final OnMarkerTappedListener onTappedListener; - private boolean consumesTapEvents; + private boolean consumeTapEvents; MarkerController( - Marker marker, boolean consumesTapEvents, OnMarkerTappedListener onTappedListener) { + Marker marker, boolean consumeTapEvents, OnMarkerTappedListener onTappedListener) { this.marker = marker; - this.consumesTapEvents = consumesTapEvents; + this.consumeTapEvents = consumeTapEvents; this.onTappedListener = onTappedListener; } @@ -25,7 +25,7 @@ if (onTappedListener != null) { onTappedListener.onMarkerTapped(marker); } - return consumesTapEvents; + return consumeTapEvents; } void remove() { @@ -43,8 +43,8 @@ } @Override - public void setConsumesTapEvents(boolean consumesTapEvents) { - this.consumesTapEvents = consumesTapEvents; + public void setConsumeTapEvents(boolean consumeTapEvents) { + this.consumeTapEvents = consumeTapEvents; } @Override @@ -68,15 +68,6 @@ } @Override - public void setInfoWindowShown(boolean infoWindowShown) { - if (infoWindowShown) { - marker.showInfoWindow(); - } else { - marker.hideInfoWindow(); - } - } - - @Override public void setInfoWindowText(String title, String snippet) { marker.setTitle(title); marker.setSnippet(snippet);
diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerOptionsSink.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerOptionsSink.java index 244a864..8b213dd 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerOptionsSink.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/MarkerOptionsSink.java
@@ -13,7 +13,7 @@ void setAnchor(float u, float v); - void setConsumesTapEvents(boolean consumesTapEvents); + void setConsumeTapEvents(boolean consumesTapEvents); void setDraggable(boolean draggable); @@ -23,8 +23,6 @@ void setInfoWindowAnchor(float u, float v); - void setInfoWindowShown(boolean shown); - void setInfoWindowText(String title, String snippet); void setPosition(LatLng position);
diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/OnCameraMoveListener.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/OnCameraMoveListener.java index ba9bf44..b78feb8 100644 --- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/OnCameraMoveListener.java +++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/OnCameraMoveListener.java
@@ -7,7 +7,7 @@ import com.google.android.gms.maps.model.CameraPosition; interface OnCameraMoveListener { - void onCameraMoveStarted(int reason); + void onCameraMoveStarted(boolean isGesture); void onCameraMove(CameraPosition newPosition);
diff --git a/packages/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj index 64d214a..6707284 100644 --- a/packages/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj
@@ -161,6 +161,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, FE7DE34E225BB9A5F4DB58C6 /* [CP] Embed Pods Frameworks */, + BB6BD9A1101E970BEF85B6D2 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -267,6 +268,24 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + BB6BD9A1101E970BEF85B6D2 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", + "${PODS_ROOT}/GoogleMaps/Maps/Frameworks/GoogleMaps.framework/Resources/GoogleMaps.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleMaps.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; FE7DE34E225BB9A5F4DB58C6 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647;
diff --git a/packages/google_maps_flutter/example/ios/Runner/AppDelegate.h b/packages/google_maps_flutter/example/ios/Runner/AppDelegate.h index 36e21bb..11a55d0 100644 --- a/packages/google_maps_flutter/example/ios/Runner/AppDelegate.h +++ b/packages/google_maps_flutter/example/ios/Runner/AppDelegate.h
@@ -1,6 +1,8 @@ #import <Flutter/Flutter.h> #import <UIKit/UIKit.h> +static NSString *const kAPIKey = @"AIzaSyBCGQ3UNVvpeJTUr07qcEmtHQmllJs4SV0"; + @interface AppDelegate : FlutterAppDelegate @end
diff --git a/packages/google_maps_flutter/example/ios/Runner/AppDelegate.m b/packages/google_maps_flutter/example/ios/Runner/AppDelegate.m index 59a72e9..fd5eb9b 100644 --- a/packages/google_maps_flutter/example/ios/Runner/AppDelegate.m +++ b/packages/google_maps_flutter/example/ios/Runner/AppDelegate.m
@@ -1,10 +1,12 @@ #include "AppDelegate.h" #include "GeneratedPluginRegistrant.h" +#import "GoogleMaps/GoogleMaps.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GMSServices provideAPIKey:kAPIKey]; [GeneratedPluginRegistrant registerWithRegistry:self]; // Override point for customization after application launch. return [super application:application didFinishLaunchingWithOptions:launchOptions];
diff --git a/packages/google_maps_flutter/example/lib/map_ui.dart b/packages/google_maps_flutter/example/lib/map_ui.dart index 64649aa..b362e32 100644 --- a/packages/google_maps_flutter/example/lib/map_ui.dart +++ b/packages/google_maps_flutter/example/lib/map_ui.dart
@@ -47,6 +47,7 @@ class MapUiBodyState extends State<MapUiBody> { CameraPosition _position; GoogleMapOptions _options; + bool _isMoving; @override void initState() { @@ -56,10 +57,12 @@ setState(() { _options = mapController.options; _position = mapController.cameraPosition; + _isMoving = mapController.isCameraMoving; }); }); _options = mapController.options; _position = mapController.cameraPosition; + _isMoving = mapController.isCameraMoving; } Widget _compassToggler() { @@ -77,17 +80,16 @@ Widget _latLngBoundsToggler() { return new FlatButton( child: new Text( - _options.latLngCameraTargetBounds.bounds == null + _options.cameraTargetBounds.bounds == null ? 'bound camera target' : 'release camera target', ), onPressed: () { widget.controller.mapController.updateMapOptions( new GoogleMapOptions( - latLngCameraTargetBounds: - _options.latLngCameraTargetBounds.bounds == null - ? const LatLngCameraTargetBounds(sydneyBounds) - : LatLngCameraTargetBounds.unbounded, + cameraTargetBounds: _options.cameraTargetBounds.bounds == null + ? const CameraTargetBounds(sydneyBounds) + : CameraTargetBounds.unbounded, ), ); }, @@ -200,6 +202,7 @@ '${_position.target.longitude.toStringAsFixed(4)}'), new Text('camera zoom: ${_position.zoom}'), new Text('camera tilt: ${_position.tilt}'), + new Text(_isMoving ? '(Camera moving)' : '(Camera idle)'), _compassToggler(), _latLngBoundsToggler(), _mapTypeCycler(),
diff --git a/packages/google_maps_flutter/example/lib/place_marker.dart b/packages/google_maps_flutter/example/lib/place_marker.dart index 0476131..b2fe8c6 100644 --- a/packages/google_maps_flutter/example/lib/place_marker.dart +++ b/packages/google_maps_flutter/example/lib/place_marker.dart
@@ -134,13 +134,6 @@ )); } - Future<void> _toggleInfoShown() async { - _selectedMarker.update( - new MarkerOptions( - infoWindowShown: !_selectedMarker.options.infoWindowShown), - ); - } - Future<void> _changeAlpha() async { final double current = _selectedMarker.options.alpha; _selectedMarker.update( @@ -198,11 +191,6 @@ onPressed: (_selectedMarker == null) ? null : _changeInfoAnchor, ), - new FlatButton( - child: const Text('toggle info shown'), - onPressed: - (_selectedMarker == null) ? null : _toggleInfoShown, - ), ], ), new Column(
diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapController.h b/packages/google_maps_flutter/ios/Classes/GoogleMapController.h new file mode 100644 index 0000000..16ea81d --- /dev/null +++ b/packages/google_maps_flutter/ios/Classes/GoogleMapController.h
@@ -0,0 +1,47 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Flutter/Flutter.h> +#import <GoogleMaps/GoogleMaps.h> +#import "GoogleMapMarkerController.h" + +// Defines events to be sent to Flutter. +@protocol FLTGoogleMapDelegate +- (void)onCameraMoveStartedOnMap:(id)mapId gesture:(BOOL)gesture; +- (void)onCameraMoveOnMap:(id)mapId cameraPosition:(GMSCameraPosition*)cameraPosition; +- (void)onCameraIdleOnMap:(id)mapId; +- (void)onMarkerTappedOnMap:(id)mapId marker:(NSString*)markerId; +@end + +// Defines map UI options writable from Flutter. +@protocol FLTGoogleMapOptionsSink +- (void)setCamera:(GMSCameraPosition*)camera; +- (void)setCameraTargetBounds:(GMSCoordinateBounds*)bounds; +- (void)setCompassEnabled:(BOOL)enabled; +- (void)setMapType:(GMSMapViewType)type; +- (void)setMinZoom:(float)minZoom maxZoom:(float)maxZoom; +- (void)setRotateGesturesEnabled:(BOOL)enabled; +- (void)setScrollGesturesEnabled:(BOOL)enabled; +- (void)setTiltGesturesEnabled:(BOOL)enabled; +- (void)setTrackCameraPosition:(BOOL)enabled; +- (void)setZoomGesturesEnabled:(BOOL)enabled; +@end + +// Defines map overlay controllable from Flutter. +@interface FLTGoogleMapController : NSObject<GMSMapViewDelegate, FLTGoogleMapOptionsSink> +@property(atomic) id<FLTGoogleMapDelegate> delegate; +@property(atomic, readonly) id mapId; ++ (instancetype)controllerWithWidth:(CGFloat)width + height:(CGFloat)height + camera:(GMSCameraPosition*)camera; +- (void)addToView:(UIView*)view; +- (void)removeFromView; +- (void)showAtX:(CGFloat)x Y:(CGFloat)y; +- (void)hide; +- (void)animateWithCameraUpdate:(GMSCameraUpdate*)cameraUpdate; +- (void)moveWithCameraUpdate:(GMSCameraUpdate*)cameraUpdate; +- (NSString*)addMarkerWithPosition:(CLLocationCoordinate2D)position; +- (FLTGoogleMapMarkerController*)markerWithId:(NSString*)markerId; +- (void)removeMarkerWithId:(NSString*)markerId; +@end
diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/ios/Classes/GoogleMapController.m new file mode 100644 index 0000000..4391106 --- /dev/null +++ b/packages/google_maps_flutter/ios/Classes/GoogleMapController.m
@@ -0,0 +1,144 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapController.h" + +static uint64_t _nextMapId = 0; + +@implementation FLTGoogleMapController { + GMSMapView* _mapView; + NSMutableDictionary* _markers; + BOOL _trackCameraPosition; +} + ++ (instancetype)controllerWithWidth:(CGFloat)width + height:(CGFloat)height + camera:(GMSCameraPosition*)camera { + GMSMapView* mapView = [GMSMapView mapWithFrame:CGRectMake(0.0, 0.0, width, height) camera:camera]; + return [[FLTGoogleMapController alloc] initWithMapView:mapView mapId:@(_nextMapId++)]; +} + +- (instancetype)initWithMapView:(GMSMapView*)mapView mapId:(id)mapId { + self = [super init]; + if (self) { + _mapView = mapView; + _mapId = mapId; + _markers = [NSMutableDictionary dictionaryWithCapacity:1]; + _trackCameraPosition = NO; + } + return self; +} + +- (void)addToView:(UIView*)view { + _mapView.hidden = YES; + _mapView.delegate = self; + [view addSubview:_mapView]; +} + +- (void)removeFromView { + [_mapView removeFromSuperview]; + _mapView.delegate = nil; +} + +- (void)showAtX:(CGFloat)x Y:(CGFloat)y { + _mapView.frame = + CGRectMake(x, y, CGRectGetWidth(_mapView.frame), CGRectGetHeight(_mapView.frame)); + _mapView.hidden = NO; +} + +- (void)hide { + _mapView.hidden = YES; +} + +- (void)animateWithCameraUpdate:(GMSCameraUpdate*)cameraUpdate { + [_mapView animateWithCameraUpdate:cameraUpdate]; +} + +- (void)moveWithCameraUpdate:(GMSCameraUpdate*)cameraUpdate { + [_mapView moveCamera:cameraUpdate]; +} + +- (NSString*)addMarkerWithPosition:(CLLocationCoordinate2D)position { + FLTGoogleMapMarkerController* markerController = + [[FLTGoogleMapMarkerController alloc] initWithPosition:position mapView:_mapView]; + _markers[markerController.markerId] = markerController; + return markerController.markerId; +} + +- (FLTGoogleMapMarkerController*)markerWithId:(NSString*)markerId { + return _markers[markerId]; +} + +- (void)removeMarkerWithId:(NSString*)markerId { + FLTGoogleMapMarkerController* markerController = _markers[markerId]; + if (markerController) { + [markerController setVisible:NO]; + [_markers removeObjectForKey:markerId]; + } +} + +#pragma mark - FLTGoogleMapOptionsSink methods + +- (void)setCamera:(GMSCameraPosition*)camera { + _mapView.camera = camera; +} + +- (void)setCameraTargetBounds:(GMSCoordinateBounds*)bounds { + _mapView.cameraTargetBounds = bounds; +} + +- (void)setCompassEnabled:(BOOL)enabled { + _mapView.settings.compassButton = enabled; +} + +- (void)setMapType:(GMSMapViewType)mapType { + _mapView.mapType = mapType; +} + +- (void)setMinZoom:(float)minZoom maxZoom:(float)maxZoom { + [_mapView setMinZoom:minZoom maxZoom:maxZoom]; +} + +- (void)setRotateGesturesEnabled:(BOOL)enabled { + _mapView.settings.rotateGestures = enabled; +} + +- (void)setScrollGesturesEnabled:(BOOL)enabled { + _mapView.settings.scrollGestures = enabled; +} + +- (void)setTiltGesturesEnabled:(BOOL)enabled { + _mapView.settings.tiltGestures = enabled; +} + +- (void)setTrackCameraPosition:(BOOL)enabled { + _trackCameraPosition = enabled; +} + +- (void)setZoomGesturesEnabled:(BOOL)enabled { + _mapView.settings.zoomGestures = enabled; +} + +#pragma mark - GMSMapViewDelegate methods + +- (void)mapView:(GMSMapView*)mapView willMove:(BOOL)gesture { + [_delegate onCameraMoveStartedOnMap:_mapId gesture:gesture]; +} + +- (void)mapView:(GMSMapView*)mapView didChangeCameraPosition:(GMSCameraPosition*)position { + if (_trackCameraPosition) { + [_delegate onCameraMoveOnMap:_mapId cameraPosition:position]; + } +} + +- (void)mapView:(GMSMapView*)mapView idleAtCameraPosition:(GMSCameraPosition*)position { + [_delegate onCameraIdleOnMap:_mapId]; +} + +- (BOOL)mapView:(GMSMapView*)mapView didTapMarker:(GMSMarker*)marker { + NSString* markerId = marker.userData[0]; + [_delegate onMarkerTappedOnMap:_mapId marker:markerId]; + return [marker.userData[1] boolValue]; +} +@end
diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h b/packages/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h new file mode 100644 index 0000000..ee724b5 --- /dev/null +++ b/packages/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h
@@ -0,0 +1,27 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Flutter/Flutter.h> +#import <GoogleMaps/GoogleMaps.h> + +// Defines marker UI options writable from Flutter. +@protocol FLTGoogleMapMarkerOptionsSink +- (void)setAlpha:(float)alpha; +- (void)setAnchor:(CGPoint)anchor; +- (void)setConsumeTapEvents:(BOOL)consume; +- (void)setDraggable:(BOOL)draggable; +- (void)setFlat:(BOOL)flat; +- (void)setIcon:(UIImage*)icon; +- (void)setInfoWindowAnchor:(CGPoint)anchor; +- (void)setInfoWindowTitle:(NSString*)title snippet:(NSString*)snippet; +- (void)setRotation:(CLLocationDegrees)rotation; +- (void)setVisible:(BOOL)visible; +- (void)setZIndex:(int)zIndex; +@end + +// Defines marker controllable by Flutter. +@interface FLTGoogleMapMarkerController : NSObject<FLTGoogleMapMarkerOptionsSink> +@property(atomic, readonly) NSString* markerId; +- (instancetype)initWithPosition:(CLLocationCoordinate2D)position mapView:(GMSMapView*)mapView; +@end
diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m b/packages/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m new file mode 100644 index 0000000..d552db9 --- /dev/null +++ b/packages/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m
@@ -0,0 +1,60 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapMarkerController.h" + +static uint64_t _nextMarkerId = 0; + +@implementation FLTGoogleMapMarkerController { + GMSMarker* _marker; + GMSMapView* _mapView; +} +- (instancetype)initWithPosition:(CLLocationCoordinate2D)position mapView:(GMSMapView*)mapView { + self = [super init]; + if (self) { + _marker = [GMSMarker markerWithPosition:position]; + _mapView = mapView; + _markerId = [NSString stringWithFormat:@"%lld", _nextMarkerId++]; + _marker.userData = @[ _markerId, @(NO) ]; + } + return self; +} + +#pragma mark - FLTGoogleMapMarkerOptionsSink methods + +- (void)setAlpha:(float)alpha { + _marker.opacity = alpha; +} +- (void)setAnchor:(CGPoint)anchor { + _marker.groundAnchor = anchor; +} +- (void)setConsumeTapEvents:(BOOL)consumes { + _marker.userData[1] = @(consumes); +} +- (void)setDraggable:(BOOL)draggable { + _marker.draggable = draggable; +} +- (void)setFlat:(BOOL)flat { + _marker.flat = flat; +} +- (void)setIcon:(UIImage*)icon { + _marker.icon = icon; +} +- (void)setInfoWindowAnchor:(CGPoint)anchor { + _marker.infoWindowAnchor = anchor; +} +- (void)setInfoWindowTitle:(NSString*)title snippet:(NSString*)snippet { + _marker.title = title; + _marker.snippet = snippet; +} +- (void)setRotation:(CLLocationDegrees)rotation { + _marker.rotation = rotation; +} +- (void)setVisible:(BOOL)visible { + _marker.map = visible ? _mapView : nil; +} +- (void)setZIndex:(int)zIndex { + _marker.zIndex = zIndex; +} +@end
diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapsPlugin.h b/packages/google_maps_flutter/ios/Classes/GoogleMapsPlugin.h index ca63565..653dfa8 100644 --- a/packages/google_maps_flutter/ios/Classes/GoogleMapsPlugin.h +++ b/packages/google_maps_flutter/ios/Classes/GoogleMapsPlugin.h
@@ -1,4 +1,11 @@ -#import <Flutter/Flutter.h> +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -@interface FLTGoogleMapsPlugin : NSObject<FlutterPlugin> +#import <Flutter/Flutter.h> +#import <GoogleMaps/GoogleMaps.h> +#import "GoogleMapController.h" +#import "GoogleMapMarkerController.h" + +@interface FLTGoogleMapsPlugin : NSObject<FlutterPlugin, FLTGoogleMapDelegate> @end
diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapsPlugin.m b/packages/google_maps_flutter/ios/Classes/GoogleMapsPlugin.m index f3b2aef..29063e9 100644 --- a/packages/google_maps_flutter/ios/Classes/GoogleMapsPlugin.m +++ b/packages/google_maps_flutter/ios/Classes/GoogleMapsPlugin.m
@@ -1,16 +1,353 @@ -#import "GoogleMapsPlugin.h" +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -@implementation FLTGoogleMapsPlugin +#import "GoogleMapsPlugin.h" +#import "GoogleMapController.h" +#import "GoogleMapMarkerController.h" + +#pragma mark - Conversion of JSON-like values sent via platform channels. Forward declarations. + +static id positionToJson(GMSCameraPosition* position); +static double toDouble(id json); +static CLLocationCoordinate2D toLocation(id json); +static GMSCameraPosition* toOptionalCameraPosition(id json); +static GMSCoordinateBounds* toOptionalBounds(id json); +static GMSCameraUpdate* toCameraUpdate(id json); +static void interpretMapOptions(id json, id<FLTGoogleMapOptionsSink> sink); +static void interpretMarkerOptions(id json, id<FLTGoogleMapMarkerOptionsSink> sink, + NSObject<FlutterPluginRegistrar>* registrar); + +#pragma mark - GoogleMaps plugin implementation + +@implementation FLTGoogleMapsPlugin { + NSObject<FlutterPluginRegistrar>* _registrar; + FlutterMethodChannel* _channel; + NSMutableDictionary* _mapControllers; +} + + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/google_maps" binaryMessenger:[registrar messenger]]; - FLTGoogleMapsPlugin* instance = [[FLTGoogleMapsPlugin alloc] init]; + FLTGoogleMapsPlugin* instance = + [[FLTGoogleMapsPlugin alloc] initWithRegistrar:registrar channel:channel]; [registrar addMethodCallDelegate:instance channel:channel]; } -- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { - result(FlutterMethodNotImplemented); +- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar + channel:(FlutterMethodChannel*)channel { + self = [super init]; + if (self) { + _registrar = registrar; + _channel = channel; + _mapControllers = [NSMutableDictionary dictionaryWithCapacity:1]; + } + return self; } +- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { + if ([call.method isEqualToString:@"init"]) { + for (FLTGoogleMapController* controller in _mapControllers.allValues) { + [controller removeFromView]; + } + [_mapControllers removeAllObjects]; + result(nil); + } else if ([call.method isEqualToString:@"createMap"]) { + NSDictionary* options = call.arguments[@"options"]; + GMSCameraPosition* camera = toOptionalCameraPosition(options[@"cameraPosition"]); + FLTGoogleMapController* controller = + [FLTGoogleMapController controllerWithWidth:toDouble(call.arguments[@"width"]) + height:toDouble(call.arguments[@"height"]) + camera:camera]; + _mapControllers[controller.mapId] = controller; + interpretMapOptions(options, controller); + UIView* flutterView = [UIApplication sharedApplication].delegate.window.rootViewController.view; + [controller addToView:flutterView]; + controller.delegate = self; + result(controller.mapId); + } else { + FlutterError* error; + FLTGoogleMapController* controller = [self mapFromCall:call error:&error]; + if (!controller) { + result(error); + return; + } + if ([call.method isEqualToString:@"showMapOverlay"]) { + [controller showAtX:toDouble(call.arguments[@"x"]) Y:toDouble(call.arguments[@"y"])]; + result(nil); + } else if ([call.method isEqualToString:@"hideMapOverlay"]) { + [controller hide]; + result(nil); + } else if ([call.method isEqualToString:@"animateCamera"]) { + [controller animateWithCameraUpdate:toCameraUpdate(call.arguments[@"cameraUpdate"])]; + result(nil); + } else if ([call.method isEqualToString:@"moveCamera"]) { + [controller moveWithCameraUpdate:toCameraUpdate(call.arguments[@"cameraUpdate"])]; + result(nil); + } else if ([call.method isEqualToString:@"updateMapOptions"]) { + interpretMapOptions(call.arguments[@"options"], controller); + result(nil); + } else if ([call.method isEqualToString:@"addMarker"]) { + NSDictionary* options = call.arguments[@"options"]; + NSString* markerId = [controller addMarkerWithPosition:toLocation(options[@"position"])]; + interpretMarkerOptions(options, [controller markerWithId:markerId], _registrar); + result(markerId); + } else if ([call.method isEqualToString:@"marker#update"]) { + interpretMarkerOptions(call.arguments[@"options"], + [controller markerWithId:call.arguments[@"marker"]], _registrar); + result(nil); + } else if ([call.method isEqualToString:@"marker#remove"]) { + [controller removeMarkerWithId:call.arguments[@"marker"]]; + result(nil); + } else { + result(FlutterMethodNotImplemented); + } + } +} + +- (FLTGoogleMapController*)mapFromCall:(FlutterMethodCall*)call error:(FlutterError**)error { + id mapId = call.arguments[@"map"]; + FLTGoogleMapController* controller = _mapControllers[mapId]; + if (!controller && error) { + *error = [FlutterError errorWithCode:@"unknown_map" message:nil details:mapId]; + } + return controller; +} + +#pragma mark - FLTGoogleMapsDelegate methods, used to send platform messages to Flutter + +- (void)onCameraMoveStartedOnMap:(id)mapId gesture:(BOOL)gesture { + [_channel invokeMethod:@"map#onCameraMoveStarted" + arguments:@{ + @"map" : mapId, + @"isGesture" : @(gesture) + }]; +} + +- (void)onCameraMoveOnMap:(id)mapId cameraPosition:(GMSCameraPosition*)cameraPosition { + [_channel invokeMethod:@"map#onCameraMove" + arguments:@{@"map" : mapId, @"position" : positionToJson(cameraPosition)}]; +} + +- (void)onCameraIdleOnMap:(id)mapId { + [_channel invokeMethod:@"map#onCameraIdle" arguments:@{@"map" : mapId}]; +} + +- (void)onMarkerTappedOnMap:(id)mapId marker:(NSString*)markerId { + [_channel invokeMethod:@"marker#onTap" arguments:@{@"map" : mapId, @"marker" : markerId}]; +} @end + +#pragma mark - Implementations of JSON conversion functions. + +static id locationToJson(CLLocationCoordinate2D position) { + return @[ @(position.latitude), @(position.longitude) ]; +} + +static id positionToJson(GMSCameraPosition* position) { + return @{ + @"target" : locationToJson([position target]), + @"zoom" : @([position zoom]), + @"bearing" : @([position bearing]), + @"tilt" : @([position viewingAngle]), + }; +} + +static bool toBool(id json) { + NSNumber* data = json; + return data.boolValue; +} + +static int toInt(id json) { + NSNumber* data = json; + return data.intValue; +} + +static double toDouble(id json) { + NSNumber* data = json; + return data.doubleValue; +} + +static float toFloat(id json) { + NSNumber* data = json; + return data.floatValue; +} + +static CLLocationCoordinate2D toLocation(id json) { + NSArray* data = json; + return CLLocationCoordinate2DMake(toDouble(data[0]), toDouble(data[1])); +} + +static CGPoint toPoint(id json) { + NSArray* data = json; + return CGPointMake(toDouble(data[0]), toDouble(data[1])); +} + +static GMSCameraPosition* toCameraPosition(id json) { + NSDictionary* data = json; + return [GMSCameraPosition cameraWithTarget:toLocation(data[@"target"]) + zoom:toFloat(data[@"zoom"]) + bearing:toDouble(data[@"bearing"]) + viewingAngle:toDouble(data[@"tilt"])]; +} + +static GMSCameraPosition* toOptionalCameraPosition(id json) { + return json ? toCameraPosition(json) : nil; +} + +static GMSCoordinateBounds* toBounds(id json) { + NSArray* data = json; + return [[GMSCoordinateBounds alloc] initWithCoordinate:toLocation(data[0]) + coordinate:toLocation(data[1])]; +} + +static GMSCoordinateBounds* toOptionalBounds(id json) { + NSArray* data = json; + return (data[0] == [NSNull null]) ? nil : toBounds(data[0]); +} + +static GMSMapViewType toMapViewType(id json) { + int value = toInt(json); + return (GMSMapViewType)(value == 0 ? 5 : value); +} + +static GMSCameraUpdate* toCameraUpdate(id json) { + NSArray* data = json; + NSString* update = data[0]; + if ([update isEqualToString:@"newCameraPosition"]) { + return [GMSCameraUpdate setCamera:toCameraPosition(data[1])]; + } else if ([update isEqualToString:@"newLatLng"]) { + return [GMSCameraUpdate setTarget:toLocation(data[1])]; + } else if ([update isEqualToString:@"newLatLngBounds"]) { + return [GMSCameraUpdate fitBounds:toBounds(data[1]) withPadding:toDouble(data[2])]; + } else if ([update isEqualToString:@"newLatLngZoom"]) { + return [GMSCameraUpdate setTarget:toLocation(data[1]) zoom:toFloat(data[2])]; + } else if ([update isEqualToString:@"scrollBy"]) { + return [GMSCameraUpdate scrollByX:toDouble(data[1]) Y:toDouble(data[2])]; + } else if ([update isEqualToString:@"zoomBy"]) { + if (data.count == 2) { + return [GMSCameraUpdate zoomBy:toFloat(data[1])]; + } else { + return [GMSCameraUpdate zoomBy:toFloat(data[1]) atPoint:toPoint(data[2])]; + } + } else if ([update isEqualToString:@"zoomIn"]) { + return [GMSCameraUpdate zoomIn]; + } else if ([update isEqualToString:@"zoomOut"]) { + return [GMSCameraUpdate zoomOut]; + } else if ([update isEqualToString:@"zoomTo"]) { + return [GMSCameraUpdate zoomTo:toFloat(data[1])]; + } + return nil; +} + +static void interpretMapOptions(id json, id<FLTGoogleMapOptionsSink> sink) { + NSDictionary* data = json; + id cameraPosition = data[@"cameraPosition"]; + if (cameraPosition) { + [sink setCamera:toCameraPosition(cameraPosition)]; + } + id cameraTargetBounds = data[@"cameraTargetBounds"]; + if (cameraTargetBounds) { + [sink setCameraTargetBounds:toOptionalBounds(cameraTargetBounds)]; + } + id compassEnabled = data[@"compassEnabled"]; + if (compassEnabled) { + [sink setCompassEnabled:toBool(compassEnabled)]; + } + id mapType = data[@"mapType"]; + if (mapType) { + [sink setMapType:toMapViewType(mapType)]; + } + id minMaxZoomPreference = data[@"minMaxZoomPreference"]; + if (minMaxZoomPreference) { + NSArray* zoomData = minMaxZoomPreference; + float minZoom = (zoomData[0] == [NSNull null]) ? kGMSMinZoomLevel : toFloat(zoomData[0]); + float maxZoom = (zoomData[1] == [NSNull null]) ? kGMSMaxZoomLevel : toFloat(zoomData[1]); + [sink setMinZoom:minZoom maxZoom:maxZoom]; + } + id rotateGesturesEnabled = data[@"rotateGesturesEnabled"]; + if (rotateGesturesEnabled) { + [sink setRotateGesturesEnabled:toBool(rotateGesturesEnabled)]; + } + id scrollGesturesEnabled = data[@"scrollGesturesEnabled"]; + if (scrollGesturesEnabled) { + [sink setScrollGesturesEnabled:toBool(scrollGesturesEnabled)]; + } + id tiltGesturesEnabled = data[@"tiltGesturesEnabled"]; + if (tiltGesturesEnabled) { + [sink setTiltGesturesEnabled:toBool(tiltGesturesEnabled)]; + } + id trackCameraPosition = data[@"trackCameraPosition"]; + if (trackCameraPosition) { + [sink setTrackCameraPosition:toBool(trackCameraPosition)]; + } + id zoomGesturesEnabled = data[@"zoomGesturesEnabled"]; + if (zoomGesturesEnabled) { + [sink setZoomGesturesEnabled:toBool(zoomGesturesEnabled)]; + } +} + +static void interpretMarkerOptions(id json, id<FLTGoogleMapMarkerOptionsSink> sink, + NSObject<FlutterPluginRegistrar>* registrar) { + NSDictionary* data = json; + id alpha = data[@"alpha"]; + if (alpha) { + [sink setAlpha:toFloat(alpha)]; + } + id anchor = data[@"anchor"]; + if (anchor) { + [sink setAnchor:toPoint(anchor)]; + } + id draggable = data[@"draggable"]; + if (draggable) { + [sink setDraggable:toBool(draggable)]; + } + id icon = data[@"icon"]; + if (icon) { + NSArray* iconData = icon; + UIImage* image; + if ([iconData[0] isEqualToString:@"defaultMarker"]) { + CGFloat hue = (iconData.count == 1) ? 0.0f : toDouble(iconData[1]); + image = [GMSMarker markerImageWithColor:[UIColor colorWithHue:hue / 360.0 + saturation:1.0 + brightness:0.7 + alpha:1.0]]; + } else if ([iconData[0] isEqualToString:@"fromAsset"]) { + if (iconData.count == 2) { + image = [UIImage imageNamed:[registrar lookupKeyForAsset:iconData[1]]]; + } else { + image = + [UIImage imageNamed:[registrar lookupKeyForAsset:iconData[1] fromPackage:iconData[2]]]; + } + } + [sink setIcon:image]; + } + id flat = data[@"flat"]; + if (flat) { + [sink setFlat:toBool(flat)]; + } + id infoWindowAnchor = data[@"infoWindowAnchor"]; + if (infoWindowAnchor) { + [sink setInfoWindowAnchor:toPoint(infoWindowAnchor)]; + } + id infoWindowText = data[@"infoWindowText"]; + if (infoWindowText) { + NSArray* infoWindowTextData = infoWindowText; + NSString* title = (infoWindowTextData[0] == [NSNull null]) ? nil : infoWindowTextData[0]; + NSString* snippet = (infoWindowTextData[1] == [NSNull null]) ? nil : infoWindowTextData[1]; + [sink setInfoWindowTitle:title snippet:snippet]; + } + id rotation = data[@"rotation"]; + if (rotation) { + [sink setRotation:toDouble(rotation)]; + } + id visible = data[@"visible"]; + if (visible) { + [sink setVisible:toBool(visible)]; + } + id zIndex = data[@"zIndex"]; + if (zIndex) { + [sink setZIndex:toInt(zIndex)]; + } +}
diff --git a/packages/google_maps_flutter/ios/google_maps_flutter.podspec b/packages/google_maps_flutter/ios/google_maps_flutter.podspec index 4fb1d2e..ca42724 100644 --- a/packages/google_maps_flutter/ios/google_maps_flutter.podspec +++ b/packages/google_maps_flutter/ios/google_maps_flutter.podspec
@@ -15,7 +15,8 @@ s.source_files = 'Classes/**/*' s.public_header_files = 'Classes/**/*.h' s.dependency 'Flutter' - + s.dependency 'GoogleMaps' + # Alternatively to the flag: use GoogleMaps as a static framework. + s.compiler_flags = '-fno-modules' s.ios.deployment_target = '8.0' end -
diff --git a/packages/google_maps_flutter/lib/src/bitmap.dart b/packages/google_maps_flutter/lib/src/bitmap.dart index 8140317..cd576fd 100644 --- a/packages/google_maps_flutter/lib/src/bitmap.dart +++ b/packages/google_maps_flutter/lib/src/bitmap.dart
@@ -43,17 +43,6 @@ } } - /// Creates a BitmapDescriptor using the name of a bitmap image file located - /// in storage private to the app. - static BitmapDescriptor fromFile(String fileName) { - return new BitmapDescriptor._(<dynamic>['fromFile', fileName]); - } - - /// Creates a BitmapDescriptor from the absolute file path of a bitmap image. - static BitmapDescriptor fromPath(String path) { - return new BitmapDescriptor._(<dynamic>['fromPath', path]); - } - final dynamic _json; dynamic _toJson() => _json;
diff --git a/packages/google_maps_flutter/lib/src/camera.dart b/packages/google_maps_flutter/lib/src/camera.dart index 525a278..e105980 100644 --- a/packages/google_maps_flutter/lib/src/camera.dart +++ b/packages/google_maps_flutter/lib/src/camera.dart
@@ -59,7 +59,7 @@ return new CameraUpdate._(<dynamic>[ 'newLatLngBounds', bounds._toJson(), - padding * window.devicePixelRatio, + padding, ]); } @@ -69,13 +69,9 @@ ); } - static CameraUpdate scrollBy(double xPixel, double yPixel) { + static CameraUpdate scrollBy(double dx, double dy) { return new CameraUpdate._( - <dynamic>[ - 'scrollBy', - xPixel * window.devicePixelRatio, - yPixel * window.devicePixelRatio, - ], + <dynamic>['scrollBy', dx, dy], ); } @@ -83,7 +79,6 @@ if (focus == null) { return new CameraUpdate._(<dynamic>['zoomBy', amount]); } else { - focus *= window.devicePixelRatio; return new CameraUpdate._(<dynamic>[ 'zoomBy', amount,
diff --git a/packages/google_maps_flutter/lib/src/controller.dart b/packages/google_maps_flutter/lib/src/controller.dart index 81b8591..dd5d8fd 100644 --- a/packages/google_maps_flutter/lib/src/controller.dart +++ b/packages/google_maps_flutter/lib/src/controller.dart
@@ -72,22 +72,22 @@ void _handleMethodCall(MethodCall call) { switch (call.method) { - case "marker#onTap": + case 'marker#onTap': final String markerId = call.arguments['marker']; final Marker marker = _markers[markerId]; if (marker != null) { onMarkerTapped(marker); } break; - case "map#onCameraMoveStarted": + case 'map#onCameraMoveStarted': _isCameraMoving = true; notifyListeners(); break; - case "map#onCameraMove": + case 'map#onCameraMove': _cameraPosition = CameraPosition._fromJson(call.arguments['position']); notifyListeners(); break; - case "map#onCameraIdle": + case 'map#onCameraIdle': _isCameraMoving = false; notifyListeners(); break; @@ -99,7 +99,7 @@ Future<void> updateMapOptions(GoogleMapOptions options) async { assert(options != null); final int id = await this.id; - await _channel.invokeMethod('setMapOptions', <String, dynamic>{ + await _channel.invokeMethod('updateMapOptions', <String, dynamic>{ 'map': id, 'options': options._toJson(), }); @@ -220,22 +220,22 @@ Completer<int> _textureId = new Completer<int>(); @override - Future<int> create(Size physicalSize) { + Future<int> create(Size size) { _textureId.complete(_channel.invokeMethod('createMap', <String, dynamic>{ - 'width': physicalSize.width, - 'height': physicalSize.height, + 'width': size.width, + 'height': size.height, 'options': options._toJson(), }).then<int>((dynamic value) => value)); return _textureId.future; } @override - Future<void> show(Offset physicalOffset) async { + Future<void> show(Offset offset) async { final int id = await _textureId.future; _channel.invokeMethod('showMapOverlay', <String, dynamic>{ 'map': id, - 'x': physicalOffset.dx, - 'y': physicalOffset.dy, + 'x': offset.dx, + 'y': offset.dy, }); }
diff --git a/packages/google_maps_flutter/lib/src/marker.dart b/packages/google_maps_flutter/lib/src/marker.dart index a3f3379..4552cf8 100644 --- a/packages/google_maps_flutter/lib/src/marker.dart +++ b/packages/google_maps_flutter/lib/src/marker.dart
@@ -33,8 +33,12 @@ MarkerOptions get options => _options; } -dynamic _offsetToJson(Offset offset) => - offset == null ? null : <dynamic>[offset.dx, offset.dy]; +dynamic _offsetToJson(Offset offset) { + if (offset == null) { + return null; + } + return <dynamic>[offset.dx, offset.dy]; +} /// Text labels for a [Marker] info window. class InfoWindowText { @@ -51,17 +55,15 @@ /// Configuration options for [Marker] instances. /// /// When used to change configuration, null values will be interpreted as -/// "do not change this configuration item". When used to represent current -/// configuration, all values will be non-null. +/// "do not change this configuration item". class MarkerOptions { final double alpha; final Offset anchor; - final bool consumesTapEvents; + final bool consumeTapEvents; final bool draggable; final bool flat; final BitmapDescriptor icon; final Offset infoWindowAnchor; - final bool infoWindowShown; final InfoWindowText infoWindowText; final LatLng position; final double rotation; @@ -71,12 +73,11 @@ const MarkerOptions({ this.alpha, this.anchor, - this.consumesTapEvents, + this.consumeTapEvents, this.draggable, this.flat, this.icon, this.infoWindowAnchor, - this.infoWindowShown, this.infoWindowText, this.position, this.rotation, @@ -87,12 +88,11 @@ static const MarkerOptions defaultOptions = const MarkerOptions( alpha: 1.0, anchor: const Offset(0.5, 1.0), - consumesTapEvents: false, + consumeTapEvents: false, draggable: false, flat: false, icon: BitmapDescriptor.defaultMarker, infoWindowAnchor: const Offset(0.5, 0.0), - infoWindowShown: false, infoWindowText: InfoWindowText.noText, rotation: 0.0, visible: true, @@ -103,12 +103,11 @@ return new MarkerOptions( alpha: changes.alpha ?? alpha, anchor: changes.anchor ?? anchor, - consumesTapEvents: changes.consumesTapEvents ?? consumesTapEvents, + consumeTapEvents: changes.consumeTapEvents ?? consumeTapEvents, draggable: changes.draggable ?? draggable, flat: changes.flat ?? flat, icon: changes.icon ?? icon, infoWindowAnchor: changes.infoWindowAnchor ?? infoWindowAnchor, - infoWindowShown: changes.infoWindowShown ?? infoWindowShown, infoWindowText: changes.infoWindowText ?? infoWindowText, position: changes.position ?? position, rotation: changes.rotation ?? rotation, @@ -118,20 +117,26 @@ } dynamic _toJson() { - return <String, dynamic>{ - 'alpha': alpha, - 'anchor': _offsetToJson(anchor), - 'consumesTapEvents': consumesTapEvents, - 'draggable': draggable, - 'flat': flat, - 'icon': icon?._toJson(), - 'infoWindowAnchor': _offsetToJson(infoWindowAnchor), - 'infoWindowShown': infoWindowShown, - 'infoWindowText': infoWindowText?._toJson(), - 'position': position?._toJson(), - 'rotation': rotation, - 'visible': visible, - 'zIndex': zIndex, - }; + final Map<String, dynamic> json = <String, dynamic>{}; + + void addIfPresent(String fieldName, dynamic value) { + if (value != null) { + json[fieldName] = value; + } + } + + addIfPresent('alpha', alpha); + addIfPresent('anchor', _offsetToJson(anchor)); + addIfPresent('consumeTapEvents', consumeTapEvents); + addIfPresent('draggable', draggable); + addIfPresent('flat', flat); + addIfPresent('icon', icon?._toJson()); + addIfPresent('infoWindowAnchor', _offsetToJson(infoWindowAnchor)); + addIfPresent('infoWindowText', infoWindowText?._toJson()); + addIfPresent('position', position?._toJson()); + addIfPresent('rotation', rotation); + addIfPresent('visible', visible); + addIfPresent('zIndex', zIndex); + return json; } }
diff --git a/packages/google_maps_flutter/lib/src/platform_overlay.dart b/packages/google_maps_flutter/lib/src/platform_overlay.dart index 2040884..f56d4bb 100644 --- a/packages/google_maps_flutter/lib/src/platform_overlay.dart +++ b/packages/google_maps_flutter/lib/src/platform_overlay.dart
@@ -63,8 +63,7 @@ return; } if (!_overlayIdCompleter.isCompleted) { - _overlayIdCompleter.complete( - overlay.create(new Size(width, height) * window.devicePixelRatio)); + _overlayIdCompleter.complete(overlay.create(new Size(width, height))); } }); } @@ -88,7 +87,7 @@ final RenderObject object = _context?.findRenderObject(); Offset offset; if (object is RenderBox) { - offset = object.localToGlobal(Offset.zero) * window.devicePixelRatio; + offset = object.localToGlobal(Offset.zero); } else { offset = Offset.zero; } @@ -207,15 +206,14 @@ /// Platform overlay. abstract class PlatformOverlay { - /// Creates a platform view of the specified [physicalSize] (in device pixels). + /// Creates a platform view of the specified [size]. /// /// The platform view should remain hidden until explicitly shown by calling /// [showOverlay]. - Future<int> create(Size physicalSize); + Future<int> create(Size size); - /// Shows the platform view at the specified [physicalOffset] (in device - /// pixels). - Future<void> show(Offset physicalOffset); + /// Shows the platform view at the specified [offset]. + Future<void> show(Offset offset); /// Hides the platform view. Future<void> hide();
diff --git a/packages/google_maps_flutter/lib/src/ui.dart b/packages/google_maps_flutter/lib/src/ui.dart index b528986..496d45b 100644 --- a/packages/google_maps_flutter/lib/src/ui.dart +++ b/packages/google_maps_flutter/lib/src/ui.dart
@@ -18,14 +18,13 @@ } /// Bounds for the map camera target. -class LatLngCameraTargetBounds { - const LatLngCameraTargetBounds(this.bounds); +class CameraTargetBounds { + const CameraTargetBounds(this.bounds); /// The current bounds or null, if the camera target is unbounded. final LatLngBounds bounds; - static const LatLngCameraTargetBounds unbounded = - const LatLngCameraTargetBounds(null); + static const CameraTargetBounds unbounded = const CameraTargetBounds(null); dynamic _toJson() => <dynamic>[bounds?._toJson()]; } @@ -50,12 +49,11 @@ /// Configuration options for the GoogleMaps user interface. /// /// When used to change configuration, null values will be interpreted as -/// "do not change this configuration item". When used to represent current -/// configuration, all values will be non-null. +/// "do not change this configuration item". class GoogleMapOptions { final CameraPosition cameraPosition; final bool compassEnabled; - final LatLngCameraTargetBounds latLngCameraTargetBounds; + final CameraTargetBounds cameraTargetBounds; final MapType mapType; final MinMaxZoomPreference minMaxZoomPreference; final bool rotateGesturesEnabled; @@ -67,7 +65,7 @@ const GoogleMapOptions({ this.cameraPosition, this.compassEnabled, - this.latLngCameraTargetBounds, + this.cameraTargetBounds, this.mapType, this.minMaxZoomPreference, this.rotateGesturesEnabled, @@ -79,7 +77,7 @@ static const GoogleMapOptions defaultOptions = const GoogleMapOptions( compassEnabled: true, - latLngCameraTargetBounds: LatLngCameraTargetBounds.unbounded, + cameraTargetBounds: CameraTargetBounds.unbounded, mapType: MapType.normal, minMaxZoomPreference: MinMaxZoomPreference.unbounded, rotateGesturesEnabled: true, @@ -93,8 +91,7 @@ return new GoogleMapOptions( cameraPosition: change.cameraPosition ?? cameraPosition, compassEnabled: change.compassEnabled ?? compassEnabled, - latLngCameraTargetBounds: - change.latLngCameraTargetBounds ?? latLngCameraTargetBounds, + cameraTargetBounds: change.cameraTargetBounds ?? cameraTargetBounds, mapType: change.mapType ?? mapType, minMaxZoomPreference: change.minMaxZoomPreference ?? minMaxZoomPreference, rotateGesturesEnabled: @@ -109,17 +106,23 @@ dynamic _toJson() { final Map<String, dynamic> json = <String, dynamic>{}; - json['cameraPosition'] = cameraPosition?._toJson(); - json['compassEnabled'] = compassEnabled; - json['latLngCameraTargetBounds'] = latLngCameraTargetBounds?._toJson(); - json['mapType'] = mapType?.index; - json['minMaxZoomPreference'] = minMaxZoomPreference?._toJson(); - json['reportCameraMoveEvents'] = trackCameraPosition; - json['rotateGesturesEnabled'] = rotateGesturesEnabled; - json['scrollGesturesEnabled'] = scrollGesturesEnabled; - json['tiltGesturesEnabled'] = tiltGesturesEnabled; - json['trackCameraPosition'] = trackCameraPosition; - json['zoomGesturesEnabled'] = zoomGesturesEnabled; + + void addIfPresent(String fieldName, dynamic value) { + if (value != null) { + json[fieldName] = value; + } + } + + addIfPresent('cameraPosition', cameraPosition?._toJson()); + addIfPresent('compassEnabled', compassEnabled); + addIfPresent('cameraTargetBounds', cameraTargetBounds?._toJson()); + addIfPresent('mapType', mapType?.index); + addIfPresent('minMaxZoomPreference', minMaxZoomPreference?._toJson()); + addIfPresent('rotateGesturesEnabled', rotateGesturesEnabled); + addIfPresent('scrollGesturesEnabled', scrollGesturesEnabled); + addIfPresent('tiltGesturesEnabled', tiltGesturesEnabled); + addIfPresent('trackCameraPosition', trackCameraPosition); + addIfPresent('zoomGesturesEnabled', zoomGesturesEnabled); return json; } }