Add GoogleMap callbacks (#507)
diff --git a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/Convert.java b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/Convert.java
index 6fd0284..5e24cff 100644
--- a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/Convert.java
+++ b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/Convert.java
@@ -7,18 +7,13 @@
import android.graphics.Point;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
-import com.google.android.gms.maps.GoogleMap;
-import com.google.android.gms.maps.GoogleMapOptions;
-import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
-import com.google.android.gms.maps.model.MarkerOptions;
import io.flutter.view.FlutterMain;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -101,62 +96,15 @@
return ((Number) o).floatValue();
}
- static GoogleMapOptions toGoogleMapOptions(Object o) {
- final Map<?, ?> data = toMap(o);
- final GoogleMapOptions options = new GoogleMapOptions();
- final Object cameraPosition = data.get("cameraPosition");
- if (cameraPosition != null) {
- options.camera(toCameraPosition(cameraPosition));
- }
- final Object cameraTargetBounds = data.get("cameraTargetBounds");
- if (cameraTargetBounds != null) {
- final List<?> targetData = toList(cameraTargetBounds);
- if (targetData.get(0) != null) {
- options.latLngBoundsForCameraTarget(toLatLngBounds(targetData.get(0)));
- }
- }
- final Object compassEnabled = data.get("compassEnabled");
- if (compassEnabled != null) {
- options.compassEnabled(toBoolean(compassEnabled));
- }
- final Object mapType = data.get("mapType");
- if (mapType != null) {
- options.mapType(toInt(mapType));
- }
- final Object rotateGesturesEnabled = data.get("rotateGesturesEnabled");
- if (rotateGesturesEnabled != null) {
- options.rotateGesturesEnabled(toBoolean(rotateGesturesEnabled));
- }
- final Object scrollGesturesEnabled = data.get("scrollGesturesEnabled");
- if (scrollGesturesEnabled != null) {
- options.scrollGesturesEnabled(toBoolean(scrollGesturesEnabled));
- }
- final Object tiltGesturesEnabled = data.get("tiltGesturesEnabled");
- if (tiltGesturesEnabled != null) {
- options.tiltGesturesEnabled(toBoolean(tiltGesturesEnabled));
- }
- final Object zoomBounds = data.get("zoomBounds");
- if (zoomBounds != null) {
- final List<?> zoomData = toList(zoomBounds);
- if (zoomData.get(0) != null) {
- options.minZoomPreference(toFloat(zoomData.get(0)));
- }
- if (zoomData.get(1) != null) {
- options.maxZoomPreference(toFloat(zoomData.get(1)));
- }
- }
- final Object zoomGesturesEnabled = data.get("zoomGesturesEnabled");
- if (zoomGesturesEnabled != null) {
- options.zoomGesturesEnabled(toBoolean(zoomGesturesEnabled));
- }
- return options;
+ private static Float toFloatWrapper(Object o) {
+ return (o == null) ? null : toFloat(o);
}
static int toInt(Object o) {
return ((Number) o).intValue();
}
- private static Object toJson(CameraPosition position) {
+ static Object toJson(CameraPosition position) {
final Map<String, Object> data = new HashMap<>();
data.put("bearing", position.bearing);
data.put("target", toJson(position.target));
@@ -175,6 +123,9 @@
}
private static LatLngBounds toLatLngBounds(Object o) {
+ if (o == null) {
+ return null;
+ }
final List<?> data = toList(o);
return new LatLngBounds(toLatLng(data.get(0)), toLatLng(data.get(1)));
}
@@ -191,25 +142,6 @@
return (Map<?, ?>) o;
}
- static MarkerOptions toMarkerOptions(Object o) {
- final Map<?, ?> data = toMap(o);
- final List<?> anchor = toList(data.get("anchor"));
- final List<?> infoWindowAnchor = toList(data.get("infoWindowAnchor"));
- return new MarkerOptions()
- .position(toLatLng(data.get("position")))
- .alpha(toFloat(data.get("alpha")))
- .anchor(toFloat(anchor.get(0)), toFloat(anchor.get(1)))
- .draggable(toBoolean(data.get("draggable")))
- .flat(toBoolean(data.get("flat")))
- .icon(toBitmapDescriptor(data.get("icon")))
- .infoWindowAnchor(toFloat(infoWindowAnchor.get(0)), toFloat(infoWindowAnchor.get(1)))
- .rotation(toFloat(data.get("rotation")))
- .snippet(toString(data.get("snippet")))
- .title(toString(data.get("title")))
- .visible(toBoolean(data.get("visible")))
- .zIndex(toFloat(data.get("zIndex")));
- }
-
private static Point toPoint(Object o) {
final List<?> data = toList(o);
return new Point(toInt(data.get(0)), toInt(data.get(1)));
@@ -219,109 +151,110 @@
return (String) o;
}
- /**
- * Sets GoogleMaps user interface options extracted from the specified JSON-like value on the
- * given GoogleMap instance.
- *
- * @param o the JSON-like value
- * @param googleMap the GoogleMap instance
- */
- static void setMapOptions(Object o, GoogleMap googleMap) {
- final Map<?, ?> options = toMap(o);
- final Object cameraTargetBounds = options.get("cameraTargetBounds");
- final UiSettings uiSettings = googleMap.getUiSettings();
- if (cameraTargetBounds != null) {
- final List<?> targetData = toList(cameraTargetBounds);
- if (targetData.get(0) == null) {
- googleMap.setLatLngBoundsForCameraTarget(null);
- } else {
- googleMap.setLatLngBoundsForCameraTarget(toLatLngBounds(targetData.get(0)));
- }
- }
- final Object compassEnabled = options.get("compassEnabled");
- if (compassEnabled != null) {
- uiSettings.setCompassEnabled(toBoolean(compassEnabled));
- }
- final Object mapType = options.get("mapType");
- if (mapType != null) {
- googleMap.setMapType(toInt(mapType));
- }
- final Object rotateGesturesEnabled = options.get("rotateGesturesEnabled");
- if (rotateGesturesEnabled != null) {
- uiSettings.setRotateGesturesEnabled(toBoolean(rotateGesturesEnabled));
- }
- final Object scrollGesturesEnabled = options.get("scrollGesturesEnabled");
- if (scrollGesturesEnabled != null) {
- uiSettings.setScrollGesturesEnabled(toBoolean(scrollGesturesEnabled));
- }
- final Object tiltGesturesEnabled = options.get("tiltGesturesEnabled");
- if (tiltGesturesEnabled != null) {
- uiSettings.setTiltGesturesEnabled(toBoolean(tiltGesturesEnabled));
- }
- final Object zoomBounds = options.get("zoomBounds");
- if (zoomBounds != null) {
- final List<?> zoomData = toList(zoomBounds);
- googleMap.resetMinMaxZoomPreference();
- if (zoomData.get(0) != null) {
- googleMap.setMinZoomPreference(toFloat(zoomData.get(0)));
- }
- if (zoomData.get(1) != null) {
- googleMap.setMaxZoomPreference(toFloat(zoomData.get(1)));
- }
- }
- final Object zoomGesturesEnabled = options.get("zoomGesturesEnabled");
- if (zoomGesturesEnabled != null) {
- uiSettings.setZoomGesturesEnabled(toBoolean(zoomGesturesEnabled));
- }
- final Object cameraPosition = options.get("cameraPosition");
+ static void interpretGoogleMapOptions(Object o, GoogleMapOptionsSink sink) {
+ final Map<?, ?> data = toMap(o);
+ final Object cameraPosition = data.get("cameraPosition");
if (cameraPosition != null) {
- googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(toCameraPosition(cameraPosition)));
+ sink.setCameraPosition(toCameraPosition(cameraPosition));
+ }
+ 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));
+ }
+ final Object minMaxZoomPreference = data.get("minMaxZoomPreference");
+ if (minMaxZoomPreference != null) {
+ final List<?> zoomPreferenceData = toList(minMaxZoomPreference);
+ sink.setMinMaxZoomPreference( //
+ toFloatWrapper(zoomPreferenceData.get(0)), //
+ toFloatWrapper(zoomPreferenceData.get(1)));
+ }
+ final Object rotateGesturesEnabled = data.get("rotateGesturesEnabled");
+ if (rotateGesturesEnabled != null) {
+ sink.setRotateGesturesEnabled(toBoolean(rotateGesturesEnabled));
+ }
+ final Object scrollGesturesEnabled = data.get("scrollGesturesEnabled");
+ if (scrollGesturesEnabled != null) {
+ sink.setScrollGesturesEnabled(toBoolean(scrollGesturesEnabled));
+ }
+ final Object tiltGesturesEnabled = data.get("tiltGesturesEnabled");
+ if (tiltGesturesEnabled != null) {
+ sink.setTiltGesturesEnabled(toBoolean(tiltGesturesEnabled));
+ }
+ final Object trackCameraPosition = data.get("trackCameraPosition");
+ if (trackCameraPosition != null) {
+ sink.setTrackCameraPosition(toBoolean(trackCameraPosition));
+ }
+ final Object zoomGesturesEnabled = data.get("zoomGesturesEnabled");
+ if (zoomGesturesEnabled != null) {
+ sink.setZoomGesturesEnabled(toBoolean(zoomGesturesEnabled));
}
}
- /**
- * Stores GoogleMaps user interface configuration items extracted from the specified JSON-like
- * value in the provided storage Map for cases where no getters exist in the GoogleMaps APIs.
- *
- * @param o the JSON-like value
- * @param storageMap the storage Map
- */
- static void setMapOptionsWithNoGetters(Object o, Map<String, Object> storageMap) {
- final Map<?, ?> options = toMap(o);
- final Object cameraTargetBounds = options.get("cameraTargetBounds");
- if (cameraTargetBounds != null) {
- storageMap.put("cameraTargetBounds", cameraTargetBounds);
+ static void interpretMarkerOptions(Object o, MarkerOptionsSink sink) {
+ final Map<?, ?> data = toMap(o);
+ final Object alpha = data.get("alpha");
+ if (alpha != null) {
+ sink.setAlpha(toFloat(alpha));
}
- final Object zoomBounds = options.get("zoomBounds");
- if (zoomBounds != null) {
- storageMap.put("zoomBounds", zoomBounds);
+ final Object anchor = data.get("anchor");
+ if (anchor != null) {
+ final List<?> anchorData = toList(anchor);
+ sink.setAnchor(toFloat(anchorData.get(0)), toFloat(anchorData.get(1)));
}
- }
-
- /**
- * Extract current GoogleMaps user interface configuration items in a JSON-like value, using the
- * specified storage Map for cases where no getters exist in the GoogleMaps APIs.
- *
- * @param googleMap a GoogleMap instance
- * @param storageMap the storage Map
- * @return a JSON-like value
- */
- static Object getMapOptions(GoogleMap googleMap, Map<String, Object> storageMap) {
- final Map<String, Object> json = new HashMap<>(storageMap);
- final UiSettings uiSettings = googleMap.getUiSettings();
- json.put("cameraPosition", toJson(googleMap.getCameraPosition()));
- if (!json.containsKey("cameraTargetBounds")) {
- json.put("cameraTargetBounds", Collections.singletonList(null)); // unbounded
+ final Object consumesTapEvents = data.get("consumesTapEvents");
+ if (consumesTapEvents != null) {
+ sink.setConsumesTapEvents(toBoolean(consumesTapEvents));
}
- json.put("compassEnabled", uiSettings.isCompassEnabled());
- json.put("mapType", googleMap.getMapType());
- json.put("rotateGesturesEnabled", uiSettings.isRotateGesturesEnabled());
- json.put("scrollGesturesEnabled", uiSettings.isScrollGesturesEnabled());
- json.put("tiltGesturesEnabled", uiSettings.isTiltGesturesEnabled());
- if (!json.containsKey("zoomBounds")) {
- json.put("zoomBounds", Arrays.asList(null, null)); // unbounded
+ final Object draggable = data.get("draggable");
+ if (draggable != null) {
+ sink.setDraggable(toBoolean(draggable));
}
- json.put("zoomGesturesEnabled", uiSettings.isZoomGesturesEnabled());
- return json;
+ final Object flat = data.get("flat");
+ if (flat != null) {
+ sink.setFlat(toBoolean(flat));
+ }
+ final Object icon = data.get("icon");
+ if (icon != null) {
+ sink.setIcon(toBitmapDescriptor(icon));
+ }
+ final Object infoWindowAnchor = data.get("infoWindowAnchor");
+ if (infoWindowAnchor != null) {
+ 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);
+ sink.setInfoWindowText(toString(textData.get(0)), toString(textData.get(1)));
+ }
+ final Object position = data.get("position");
+ if (position != null) {
+ sink.setPosition(toLatLng(position));
+ }
+ final Object rotation = data.get("rotation");
+ if (rotation != null) {
+ sink.setRotation(toFloat(rotation));
+ }
+ final Object visible = data.get("visible");
+ if (visible != null) {
+ sink.setVisible(toBoolean(visible));
+ }
+ final Object zIndex = data.get("zIndex");
+ if (zIndex != null) {
+ sink.setZIndex(toFloat(zIndex));
+ }
}
}
diff --git a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMapBuilder.java b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMapBuilder.java
new file mode 100644
index 0000000..87ac319
--- /dev/null
+++ b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMapBuilder.java
@@ -0,0 +1,85 @@
+// 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.
+
+package io.flutter.plugins.googlemobilemaps;
+
+import com.google.android.gms.maps.GoogleMapOptions;
+import com.google.android.gms.maps.model.CameraPosition;
+import com.google.android.gms.maps.model.LatLngBounds;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugin.common.PluginRegistry;
+import java.util.concurrent.atomic.AtomicInteger;
+
+class GoogleMapBuilder implements GoogleMapOptionsSink {
+ private final GoogleMapOptions options = new GoogleMapOptions();
+ private boolean trackCameraPosition = false;
+
+ GoogleMapController build(
+ AtomicInteger state,
+ PluginRegistry.Registrar registrar,
+ int width,
+ int height,
+ MethodChannel.Result result) {
+ final GoogleMapController controller =
+ new GoogleMapController(state, registrar, width, height, options, result);
+ controller.init();
+ controller.setTrackCameraPosition(trackCameraPosition);
+ return controller;
+ }
+
+ @Override
+ public void setCameraPosition(CameraPosition position) {
+ options.camera(position);
+ }
+
+ @Override
+ public void setCompassEnabled(boolean compassEnabled) {
+ options.compassEnabled(compassEnabled);
+ }
+
+ @Override
+ public void setLatLngBoundsForCameraTarget(LatLngBounds bounds) {
+ options.latLngBoundsForCameraTarget(bounds);
+ }
+
+ @Override
+ public void setMapType(int mapType) {
+ options.mapType(mapType);
+ }
+
+ @Override
+ public void setMinMaxZoomPreference(Float min, Float max) {
+ if (min != null) {
+ options.minZoomPreference(min);
+ }
+ if (max != null) {
+ options.maxZoomPreference(max);
+ }
+ }
+
+ @Override
+ public void setTrackCameraPosition(boolean trackCameraPosition) {
+ this.trackCameraPosition = trackCameraPosition;
+ }
+
+ @Override
+ public void setRotateGesturesEnabled(boolean rotateGesturesEnabled) {
+ options.rotateGesturesEnabled(rotateGesturesEnabled);
+ }
+
+ @Override
+ public void setScrollGesturesEnabled(boolean scrollGesturesEnabled) {
+ options.scrollGesturesEnabled(scrollGesturesEnabled);
+ }
+
+ @Override
+ public void setTiltGesturesEnabled(boolean tiltGesturesEnabled) {
+ options.tiltGesturesEnabled(tiltGesturesEnabled);
+ }
+
+ @Override
+ public void setZoomGesturesEnabled(boolean zoomGesturesEnabled) {
+ options.zoomGesturesEnabled(zoomGesturesEnabled);
+ }
+}
diff --git a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMapController.java b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMapController.java
index 4ae0a90..3f6114d 100644
--- a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMapController.java
+++ b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMapController.java
@@ -19,9 +19,13 @@
import android.view.Surface;
import android.widget.FrameLayout;
import com.google.android.gms.maps.CameraUpdate;
+import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.GoogleMapOptions;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.OnMapReadyCallback;
+import com.google.android.gms.maps.model.CameraPosition;
+import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import io.flutter.plugin.common.MethodChannel;
@@ -38,9 +42,12 @@
/** Controller of a single GoogleMaps MapView instance. */
final class GoogleMapController
implements Application.ActivityLifecycleCallbacks,
+ GoogleMapOptionsSink,
OnMapReadyCallback,
GoogleMap.SnapshotReadyCallback,
+ GoogleMap.OnMarkerClickListener,
GoogleMap.OnCameraMoveStartedListener,
+ GoogleMap.OnCameraMoveListener,
GoogleMap.OnCameraIdleListener {
private final AtomicInteger activityState;
private final FrameLayout parent;
@@ -52,10 +59,12 @@
private final int height;
private final MethodChannel.Result result;
private final Timer timer;
- private final Map<String, Marker> markers;
- private final Map<String, Object> optionsStorage;
+ private final Map<String, MarkerController> markers;
+ private OnMarkerTappedListener onMarkerTappedListener;
+ private OnCameraMoveListener onCameraMoveListener;
private GoogleMap googleMap;
private Surface surface;
+ private boolean trackCameraPosition = false;
private boolean disposed = false;
GoogleMapController(
@@ -63,7 +72,7 @@
PluginRegistry.Registrar registrar,
int width,
int height,
- Object options,
+ GoogleMapOptions options,
MethodChannel.Result result) {
this.activityState = activityState;
this.registrar = registrar;
@@ -75,11 +84,17 @@
this.textureEntry = registrar.textures().createSurfaceTexture();
this.surface = new Surface(textureEntry.surfaceTexture());
textureEntry.surfaceTexture().setDefaultBufferSize(width, height);
- this.mapView = new MapView(registrar.activity(), Convert.toGoogleMapOptions(options));
+ this.mapView = new MapView(registrar.activity(), options);
this.timer = new Timer();
this.markers = new HashMap<>();
- this.optionsStorage = new HashMap<>();
- Convert.setMapOptionsWithNoGetters(options, optionsStorage);
+ }
+
+ void setOnCameraMoveListener(OnCameraMoveListener listener) {
+ this.onCameraMoveListener = listener;
+ }
+
+ void setOnMarkerTappedListener(OnMarkerTappedListener listener) {
+ this.onMarkerTappedListener = listener;
}
void init() {
@@ -140,15 +155,6 @@
parent.addView(mapView, 0);
}
- void setMapOptions(Object json) {
- Convert.setMapOptions(json, googleMap);
- Convert.setMapOptionsWithNoGetters(json, optionsStorage);
- }
-
- Object getMapOptions() {
- return Convert.getMapOptions(googleMap, optionsStorage);
- }
-
void moveCamera(CameraUpdate cameraUpdate) {
googleMap.moveCamera(cameraUpdate);
}
@@ -157,47 +163,26 @@
googleMap.animateCamera(cameraUpdate);
}
- String addMarker(MarkerOptions options) {
- final Marker marker = googleMap.addMarker(options);
- markers.put(marker.getId(), marker);
- return marker.getId();
+ MarkerBuilder newMarkerBuilder() {
+ return new MarkerBuilder(this);
+ }
+
+ Marker addMarker(MarkerOptions markerOptions, boolean consumesTapEvents) {
+ final Marker marker = googleMap.addMarker(markerOptions);
+ markers.put(
+ marker.getId(), new MarkerController(marker, consumesTapEvents, onMarkerTappedListener));
+ return marker;
}
void removeMarker(String markerId) {
- final Marker marker = markers.remove(markerId);
- if (marker != null) {
- marker.remove();
+ final MarkerController markerController = markers.remove(markerId);
+ if (markerController != null) {
+ markerController.remove();
}
}
- void showMarkerInfoWindow(String markerId) {
- final Marker marker = marker(markerId);
- marker.showInfoWindow();
- }
-
- void hideMarkerInfoWindow(String markerId) {
- final Marker marker = marker(markerId);
- marker.hideInfoWindow();
- }
-
- void updateMarker(String markerId, MarkerOptions options) {
- final Marker marker = marker(markerId);
- marker.setPosition(options.getPosition());
- marker.setAlpha(options.getAlpha());
- marker.setAnchor(options.getAnchorU(), options.getAnchorV());
- marker.setDraggable(options.isDraggable());
- marker.setFlat(options.isFlat());
- marker.setIcon(options.getIcon());
- marker.setInfoWindowAnchor(options.getInfoWindowAnchorU(), options.getInfoWindowAnchorV());
- marker.setRotation(options.getRotation());
- marker.setSnippet(options.getSnippet());
- marker.setTitle(options.getTitle());
- marker.setVisible(options.isVisible());
- marker.setZIndex(options.getZIndex());
- }
-
- private Marker marker(String markerId) {
- final Marker marker = markers.get(markerId);
+ MarkerController marker(String markerId) {
+ final MarkerController marker = markers.get(markerId);
if (marker == null) {
throw new IllegalArgumentException("Unknown marker: " + markerId);
}
@@ -218,7 +203,9 @@
this.googleMap = googleMap;
result.success(id());
googleMap.setOnCameraMoveStartedListener(this);
+ googleMap.setOnCameraMoveListener(this);
googleMap.setOnCameraIdleListener(this);
+ googleMap.setOnMarkerClickListener(this);
// Take snapshots until the dust settles.
timer.schedule(newSnapshotTask(), 0);
timer.schedule(newSnapshotTask(), 500);
@@ -229,11 +216,20 @@
@Override
public void onCameraMoveStarted(int reason) {
+ onCameraMoveListener.onCameraMoveStarted(reason);
cancelSnapshotTimerTasks();
}
@Override
+ public void onCameraMove() {
+ if (trackCameraPosition && onCameraMoveListener != null) {
+ onCameraMoveListener.onCameraMove(googleMap.getCameraPosition());
+ }
+ }
+
+ @Override
public void onCameraIdle() {
+ onCameraMoveListener.onCameraIdle();
// Take snapshots until the dust settles.
timer.schedule(newSnapshotTask(), 500);
timer.schedule(newSnapshotTask(), 1500);
@@ -241,6 +237,12 @@
}
@Override
+ public boolean onMarkerClick(Marker marker) {
+ final MarkerController markerController = markers.get(marker.getId());
+ return (markerController != null && markerController.onTap());
+ }
+
+ @Override
public void onSnapshotReady(Bitmap bitmap) {
updateTexture();
}
@@ -337,4 +339,62 @@
googleMap.snapshot(GoogleMapController.this, bitmap);
}
}
+
+ // GoogleMapOptionsSink methods
+
+ @Override
+ public void setCameraPosition(CameraPosition position) {
+ googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(position));
+ }
+
+ @Override
+ public void setCompassEnabled(boolean compassEnabled) {
+ googleMap.getUiSettings().setCompassEnabled(compassEnabled);
+ }
+
+ @Override
+ public void setMapType(int mapType) {
+ googleMap.setMapType(mapType);
+ }
+
+ @Override
+ public void setLatLngBoundsForCameraTarget(LatLngBounds bounds) {
+ googleMap.setLatLngBoundsForCameraTarget(bounds);
+ }
+
+ @Override
+ public void setTrackCameraPosition(boolean trackCameraPosition) {
+ this.trackCameraPosition = trackCameraPosition;
+ }
+
+ @Override
+ public void setRotateGesturesEnabled(boolean rotateGesturesEnabled) {
+ googleMap.getUiSettings().setRotateGesturesEnabled(rotateGesturesEnabled);
+ }
+
+ @Override
+ public void setScrollGesturesEnabled(boolean scrollGesturesEnabled) {
+ googleMap.getUiSettings().setScrollGesturesEnabled(scrollGesturesEnabled);
+ }
+
+ @Override
+ public void setTiltGesturesEnabled(boolean tiltGesturesEnabled) {
+ googleMap.getUiSettings().setTiltGesturesEnabled(tiltGesturesEnabled);
+ }
+
+ @Override
+ public void setMinMaxZoomPreference(Float min, Float max) {
+ googleMap.resetMinMaxZoomPreference();
+ if (min != null) {
+ googleMap.setMinZoomPreference(min);
+ }
+ if (max != null) {
+ googleMap.setMaxZoomPreference(max);
+ }
+ }
+
+ @Override
+ public void setZoomGesturesEnabled(boolean zoomGesturesEnabled) {
+ googleMap.getUiSettings().setZoomGesturesEnabled(zoomGesturesEnabled);
+ }
}
diff --git a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMapOptionsSink.java b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMapOptionsSink.java
new file mode 100644
index 0000000..6eb764d
--- /dev/null
+++ b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMapOptionsSink.java
@@ -0,0 +1,31 @@
+// 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.
+
+package io.flutter.plugins.googlemobilemaps;
+
+import com.google.android.gms.maps.model.CameraPosition;
+import com.google.android.gms.maps.model.LatLngBounds;
+
+/** Receiver of GoogleMap configuration options. */
+interface GoogleMapOptionsSink {
+ void setCameraPosition(CameraPosition position);
+
+ void setLatLngBoundsForCameraTarget(LatLngBounds bounds);
+
+ void setCompassEnabled(boolean compassEnabled);
+
+ void setMapType(int mapType);
+
+ void setTrackCameraPosition(boolean reportCameraMoveEvents);
+
+ void setRotateGesturesEnabled(boolean rotateGesturesEnabled);
+
+ void setScrollGesturesEnabled(boolean scrollGesturesEnabled);
+
+ void setTiltGesturesEnabled(boolean tiltGesturesEnabled);
+
+ void setMinMaxZoomPreference(Float min, Float max);
+
+ void setZoomGesturesEnabled(boolean zoomGesturesEnabled);
+}
diff --git a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMobileMapsPlugin.java b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMobileMapsPlugin.java
index e581a89..542f1aa 100644
--- a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMobileMapsPlugin.java
+++ b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/GoogleMobileMapsPlugin.java
@@ -8,16 +8,24 @@
import android.app.Application;
import android.os.Bundle;
import com.google.android.gms.maps.CameraUpdate;
-import com.google.android.gms.maps.model.MarkerOptions;
+import com.google.android.gms.maps.model.CameraPosition;
+import com.google.android.gms.maps.model.Marker;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
+/**
+ * Plugin for controlling a set of GoogleMap views to be shown as overlays on top of the Flutter
+ * view. The overlay should be hidden during transformations or while Flutter is rendering on top of
+ * the map. A Texture drawn using GoogleMap bitmap snapshots can then be shown instead of the
+ * overlay.
+ */
public class GoogleMobileMapsPlugin
implements MethodCallHandler, Application.ActivityLifecycleCallbacks {
static final int CREATED = 1;
@@ -28,18 +36,20 @@
static final int DESTROYED = 6;
private final Map<Long, GoogleMapController> googleMaps = new HashMap<>();
private final Registrar registrar;
+ private final MethodChannel channel;
private final AtomicInteger state = new AtomicInteger(0);
public static void registerWith(Registrar registrar) {
- final GoogleMobileMapsPlugin plugin = new GoogleMobileMapsPlugin(registrar);
final MethodChannel channel =
new MethodChannel(registrar.messenger(), "plugins.flutter.io/google_mobile_maps");
+ final GoogleMobileMapsPlugin plugin = new GoogleMobileMapsPlugin(registrar, channel);
channel.setMethodCallHandler(plugin);
registrar.activity().getApplication().registerActivityLifecycleCallbacks(plugin);
}
- private GoogleMobileMapsPlugin(Registrar registrar) {
+ private GoogleMobileMapsPlugin(Registrar registrar, MethodChannel channel) {
this.registrar = registrar;
+ this.channel = channel;
}
@Override
@@ -59,23 +69,52 @@
final int width = Convert.toInt(call.argument("width"));
final int height = Convert.toInt(call.argument("height"));
final Map<?, ?> options = Convert.toMap(call.argument("options"));
+ final GoogleMapBuilder builder = new GoogleMapBuilder();
+ Convert.interpretGoogleMapOptions(options, builder);
final GoogleMapController controller =
- new GoogleMapController(state, registrar, width, height, options, result);
+ builder.build(state, registrar, width, height, result);
googleMaps.put(controller.id(), controller);
- controller.init();
+ controller.setOnCameraMoveListener(
+ new OnCameraMoveListener() {
+ @Override
+ public void onCameraMoveStarted(int reason) {
+ final Map<String, Object> arguments = new HashMap<>(2);
+ arguments.put("map", controller.id());
+ arguments.put("reason", reason);
+ channel.invokeMethod("map#onCameraMoveStarted", arguments);
+ }
+
+ @Override
+ public void onCameraMove(CameraPosition position) {
+ final Map<String, Object> arguments = new HashMap<>(2);
+ arguments.put("map", controller.id());
+ arguments.put("position", Convert.toJson(position));
+ channel.invokeMethod("map#onCameraMove", arguments);
+ }
+
+ @Override
+ public void onCameraIdle() {
+ channel.invokeMethod(
+ "map#onCameraIdle", Collections.singletonMap("map", controller.id()));
+ }
+ });
+ controller.setOnMarkerTappedListener(
+ new OnMarkerTappedListener() {
+ @Override
+ public void onMarkerTapped(Marker marker) {
+ final Map<String, Object> arguments = new HashMap<>(2);
+ arguments.put("map", controller.id());
+ arguments.put("marker", marker.getId());
+ channel.invokeMethod("marker#onTap", arguments);
+ }
+ });
// result.success is called from controller when the GoogleMaps instance is ready
break;
}
- case "getMapOptions":
- {
- final GoogleMapController controller = mapsController(call);
- result.success(controller.getMapOptions());
- break;
- }
case "setMapOptions":
{
final GoogleMapController controller = mapsController(call);
- controller.setMapOptions(call.argument("options"));
+ Convert.interpretGoogleMapOptions(call.argument("options"), controller);
result.success(null);
break;
}
@@ -98,9 +137,9 @@
case "addMarker":
{
final GoogleMapController controller = mapsController(call);
- final MarkerOptions markerOptions =
- Convert.toMarkerOptions(call.argument("markerOptions"));
- final String markerId = controller.addMarker(markerOptions);
+ final MarkerBuilder markerBuilder = controller.newMarkerBuilder();
+ Convert.interpretMarkerOptions(call.argument("options"), markerBuilder);
+ final String markerId = markerBuilder.build();
result.success(markerId);
break;
}
@@ -112,29 +151,12 @@
result.success(null);
break;
}
- case "marker#hideInfoWindow":
- {
- final GoogleMapController controller = mapsController(call);
- final String markerId = call.argument("marker");
- controller.hideMarkerInfoWindow(markerId);
- result.success(null);
- break;
- }
- case "marker#showInfoWindow":
- {
- final GoogleMapController controller = mapsController(call);
- final String markerId = call.argument("marker");
- controller.showMarkerInfoWindow(markerId);
- result.success(null);
- break;
- }
case "marker#update":
{
final GoogleMapController controller = mapsController(call);
final String markerId = call.argument("marker");
- final MarkerOptions markerOptions =
- Convert.toMarkerOptions(call.argument("markerOptions"));
- controller.updateMarker(markerId, markerOptions);
+ final MarkerController marker = controller.marker(markerId);
+ Convert.interpretMarkerOptions(call.argument("options"), marker);
result.success(null);
break;
}
diff --git a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/MarkerBuilder.java b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/MarkerBuilder.java
new file mode 100644
index 0000000..dc06eb7
--- /dev/null
+++ b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/MarkerBuilder.java
@@ -0,0 +1,96 @@
+// 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.
+
+package io.flutter.plugins.googlemobilemaps;
+
+import com.google.android.gms.maps.model.BitmapDescriptor;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Marker;
+import com.google.android.gms.maps.model.MarkerOptions;
+
+class MarkerBuilder implements MarkerOptionsSink {
+ private final GoogleMapController mapController;
+ private final MarkerOptions markerOptions;
+ private boolean consumesTapEvents;
+ private boolean infoWindowShown;
+
+ MarkerBuilder(GoogleMapController mapController) {
+ this.mapController = mapController;
+ this.markerOptions = new MarkerOptions();
+ }
+
+ String build() {
+ final Marker marker = mapController.addMarker(markerOptions, consumesTapEvents);
+ if (infoWindowShown) {
+ marker.showInfoWindow();
+ }
+ return marker.getId();
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ markerOptions.alpha(alpha);
+ }
+
+ @Override
+ public void setAnchor(float u, float v) {
+ markerOptions.anchor(u, v);
+ }
+
+ @Override
+ public void setConsumesTapEvents(boolean consumesTapEvents) {
+ this.consumesTapEvents = consumesTapEvents;
+ }
+
+ @Override
+ public void setDraggable(boolean draggable) {
+ markerOptions.draggable(draggable);
+ }
+
+ @Override
+ public void setFlat(boolean flat) {
+ markerOptions.flat(flat);
+ }
+
+ @Override
+ public void setIcon(BitmapDescriptor bitmapDescriptor) {
+ markerOptions.icon(bitmapDescriptor);
+ }
+
+ @Override
+ public void setInfoWindowAnchor(float u, float v) {
+ markerOptions.infoWindowAnchor(u, v);
+ }
+
+ @Override
+ public void setInfoWindowShown(boolean infoWindowShown) {
+ this.infoWindowShown = infoWindowShown;
+ }
+
+ @Override
+ public void setInfoWindowText(String title, String snippet) {
+ markerOptions.title(title);
+ markerOptions.snippet(snippet);
+ }
+
+ @Override
+ public void setPosition(LatLng position) {
+ markerOptions.position(position);
+ }
+
+ @Override
+ public void setRotation(float rotation) {
+ markerOptions.rotation(rotation);
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ markerOptions.visible(visible);
+ }
+
+ @Override
+ public void setZIndex(float zIndex) {
+ markerOptions.zIndex(zIndex);
+ }
+}
diff --git a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/MarkerController.java b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/MarkerController.java
new file mode 100644
index 0000000..bd6e660
--- /dev/null
+++ b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/MarkerController.java
@@ -0,0 +1,104 @@
+// 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.
+
+package io.flutter.plugins.googlemobilemaps;
+
+import com.google.android.gms.maps.model.BitmapDescriptor;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Marker;
+
+/** Controller of a single Marker on the map. */
+class MarkerController implements MarkerOptionsSink {
+ private final Marker marker;
+ private final OnMarkerTappedListener onTappedListener;
+ private boolean consumesTapEvents;
+
+ MarkerController(
+ Marker marker, boolean consumesTapEvents, OnMarkerTappedListener onTappedListener) {
+ this.marker = marker;
+ this.consumesTapEvents = consumesTapEvents;
+ this.onTappedListener = onTappedListener;
+ }
+
+ boolean onTap() {
+ if (onTappedListener != null) {
+ onTappedListener.onMarkerTapped(marker);
+ }
+ return consumesTapEvents;
+ }
+
+ void remove() {
+ marker.remove();
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ marker.setAlpha(alpha);
+ }
+
+ @Override
+ public void setAnchor(float u, float v) {
+ marker.setAnchor(u, v);
+ }
+
+ @Override
+ public void setConsumesTapEvents(boolean consumesTapEvents) {
+ this.consumesTapEvents = consumesTapEvents;
+ }
+
+ @Override
+ public void setDraggable(boolean draggable) {
+ marker.setDraggable(draggable);
+ }
+
+ @Override
+ public void setFlat(boolean flat) {
+ marker.setFlat(flat);
+ }
+
+ @Override
+ public void setIcon(BitmapDescriptor bitmapDescriptor) {
+ marker.setIcon(bitmapDescriptor);
+ }
+
+ @Override
+ public void setInfoWindowAnchor(float u, float v) {
+ marker.setInfoWindowAnchor(u, v);
+ }
+
+ @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);
+ }
+
+ @Override
+ public void setPosition(LatLng position) {
+ marker.setPosition(position);
+ }
+
+ @Override
+ public void setRotation(float rotation) {
+ marker.setRotation(rotation);
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ marker.setVisible(visible);
+ }
+
+ @Override
+ public void setZIndex(float zIndex) {
+ marker.setZIndex(zIndex);
+ }
+}
diff --git a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/MarkerOptionsSink.java b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/MarkerOptionsSink.java
new file mode 100644
index 0000000..7499e40
--- /dev/null
+++ b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/MarkerOptionsSink.java
@@ -0,0 +1,37 @@
+// 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.
+
+package io.flutter.plugins.googlemobilemaps;
+
+import com.google.android.gms.maps.model.BitmapDescriptor;
+import com.google.android.gms.maps.model.LatLng;
+
+/** Receiver of Marker configuration options. */
+interface MarkerOptionsSink {
+ void setAlpha(float alpha);
+
+ void setAnchor(float u, float v);
+
+ void setConsumesTapEvents(boolean consumesTapEvents);
+
+ void setDraggable(boolean draggable);
+
+ void setFlat(boolean flat);
+
+ void setIcon(BitmapDescriptor bitmapDescriptor);
+
+ void setInfoWindowAnchor(float u, float v);
+
+ void setInfoWindowShown(boolean shown);
+
+ void setInfoWindowText(String title, String snippet);
+
+ void setPosition(LatLng position);
+
+ void setRotation(float rotation);
+
+ void setVisible(boolean visible);
+
+ void setZIndex(float zIndex);
+}
diff --git a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/OnCameraMoveListener.java b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/OnCameraMoveListener.java
new file mode 100644
index 0000000..671c9f2
--- /dev/null
+++ b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/OnCameraMoveListener.java
@@ -0,0 +1,15 @@
+// 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.
+
+package io.flutter.plugins.googlemobilemaps;
+
+import com.google.android.gms.maps.model.CameraPosition;
+
+interface OnCameraMoveListener {
+ void onCameraMoveStarted(int reason);
+
+ void onCameraMove(CameraPosition newPosition);
+
+ void onCameraIdle();
+}
diff --git a/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/OnMarkerTappedListener.java b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/OnMarkerTappedListener.java
new file mode 100644
index 0000000..ce9319c
--- /dev/null
+++ b/packages/google_mobile_maps/android/src/main/java/io/flutter/plugins/googlemobilemaps/OnMarkerTappedListener.java
@@ -0,0 +1,11 @@
+// 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.
+
+package io.flutter.plugins.googlemobilemaps;
+
+import com.google.android.gms.maps.model.Marker;
+
+interface OnMarkerTappedListener {
+ void onMarkerTapped(Marker marker);
+}
diff --git a/packages/google_mobile_maps/example/lib/animate_camera.dart b/packages/google_mobile_maps/example/lib/animate_camera.dart
index f867e86..abb9f1d 100644
--- a/packages/google_mobile_maps/example/lib/animate_camera.dart
+++ b/packages/google_mobile_maps/example/lib/animate_camera.dart
@@ -11,12 +11,9 @@
AnimateCameraPage()
: super(const Icon(Icons.map), "Camera control, animated");
- final GoogleMapsOverlayController controller =
- new GoogleMapsOverlayController.fromSize(width: 300.0, height: 200.0);
-
@override
- PlatformOverlayController get overlayController =>
- controller.overlayController;
+ final GoogleMapOverlayController controller =
+ new GoogleMapOverlayController.fromSize(width: 300.0, height: 200.0);
@override
Widget build(BuildContext context) {
@@ -24,7 +21,7 @@
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
- new Center(child: new GoogleMapsOverlay(controller: controller)),
+ new Center(child: new GoogleMapOverlay(controller: controller)),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
@@ -32,7 +29,7 @@
children: <Widget>[
new FlatButton(
onPressed: () {
- controller.mapsController.animateCamera(
+ controller.mapController.animateCamera(
CameraUpdate.newCameraPosition(
const CameraPosition(
bearing: 270.0,
@@ -47,7 +44,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.animateCamera(
+ controller.mapController.animateCamera(
CameraUpdate.newLatLng(
const LatLng(56.1725505, 10.1850512),
),
@@ -57,7 +54,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.animateCamera(
+ controller.mapController.animateCamera(
CameraUpdate.newLatLngBounds(
const LatLngBounds(
southwest: const LatLng(-38.483935, 113.248673),
@@ -71,7 +68,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.animateCamera(
+ controller.mapController.animateCamera(
CameraUpdate.newLatLngZoom(
const LatLng(37.4231613, -122.087159),
11.0,
@@ -82,7 +79,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.animateCamera(
+ controller.mapController.animateCamera(
CameraUpdate.scrollBy(150.0, -225.0),
);
},
@@ -94,7 +91,7 @@
children: <Widget>[
new FlatButton(
onPressed: () {
- controller.mapsController.animateCamera(
+ controller.mapController.animateCamera(
CameraUpdate.zoomBy(
-0.5,
const Offset(30.0, 20.0),
@@ -105,7 +102,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.animateCamera(
+ controller.mapController.animateCamera(
CameraUpdate.zoomBy(-0.5),
);
},
@@ -113,7 +110,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.animateCamera(
+ controller.mapController.animateCamera(
CameraUpdate.zoomIn(),
);
},
@@ -121,7 +118,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.animateCamera(
+ controller.mapController.animateCamera(
CameraUpdate.zoomOut(),
);
},
@@ -129,7 +126,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.animateCamera(
+ controller.mapController.animateCamera(
CameraUpdate.zoomTo(16.0),
);
},
diff --git a/packages/google_mobile_maps/example/lib/main.dart b/packages/google_mobile_maps/example/lib/main.dart
index f22e075..63c28b4 100644
--- a/packages/google_mobile_maps/example/lib/main.dart
+++ b/packages/google_mobile_maps/example/lib/main.dart
@@ -43,10 +43,10 @@
}
void main() {
- GoogleMapsController.init();
+ GoogleMapController.init();
final List<NavigatorObserver> observers = <NavigatorObserver>[];
for (Page p in _allPages) {
- observers.add(p.overlayController);
+ observers.add(p.controller.overlayController);
}
runApp(new MaterialApp(home: new MapsDemo(), navigatorObservers: observers));
}
diff --git a/packages/google_mobile_maps/example/lib/map_ui.dart b/packages/google_mobile_maps/example/lib/map_ui.dart
index 6565caa..3fc73ec 100644
--- a/packages/google_mobile_maps/example/lib/map_ui.dart
+++ b/packages/google_mobile_maps/example/lib/map_ui.dart
@@ -15,8 +15,9 @@
class MapUiPage extends Page {
MapUiPage() : super(const Icon(Icons.map), "User interface");
- final GoogleMapsOverlayController controller =
- new GoogleMapsOverlayController.fromSize(
+ @override
+ final GoogleMapOverlayController controller =
+ new GoogleMapOverlayController.fromSize(
width: 300.0,
height: 200.0,
options: const GoogleMapOptions(
@@ -24,21 +25,18 @@
target: const LatLng(-33.852, 151.211),
zoom: 11.0,
),
+ trackCameraPosition: true,
),
);
@override
- PlatformOverlayController get overlayController =>
- controller.overlayController;
-
- @override
Widget build(BuildContext context) {
return new MapUiBody(controller);
}
}
class MapUiBody extends StatefulWidget {
- final GoogleMapsOverlayController controller;
+ final GoogleMapOverlayController controller;
const MapUiBody(this.controller);
@@ -47,144 +45,141 @@
}
class MapUiBodyState extends State<MapUiBody> {
- Future<GoogleMapOptions> _optionsFuture;
+ CameraPosition _position;
+ GoogleMapOptions _options;
@override
void initState() {
super.initState();
- _optionsFuture = widget.controller.mapsController.getMapOptions();
+ final GoogleMapController mapController = widget.controller.mapController;
+ mapController.addListener(() {
+ setState(() {
+ _options = mapController.options;
+ _position = mapController.cameraPosition;
+ });
+ });
+ _options = mapController.options;
+ _position = mapController.cameraPosition;
}
- Widget _compassToggler(GoogleMapOptions options) {
+ Widget _compassToggler() {
return new FlatButton(
child:
- new Text('${options.compassEnabled ? 'disable' : 'enable'} compass'),
- onPressed: () async {
- await widget.controller.mapsController.setMapOptions(
- new GoogleMapOptions(compassEnabled: !options.compassEnabled),
+ new Text('${_options.compassEnabled ? 'disable' : 'enable'} compass'),
+ onPressed: () {
+ widget.controller.mapController.updateMapOptions(
+ new GoogleMapOptions(compassEnabled: !_options.compassEnabled),
);
- _reloadOptions();
},
);
}
- Widget _latLngBoundsToggler(GoogleMapOptions options) {
+ Widget _latLngBoundsToggler() {
return new FlatButton(
child: new Text(
- options.cameraTargetBounds.isBounded
- ? 'release camera target'
- : 'bound camera target',
+ _options.latLngCameraTargetBounds.bounds == null
+ ? 'bound camera target'
+ : 'release camera target',
),
- onPressed: () async {
- await widget.controller.mapsController.setMapOptions(
+ onPressed: () {
+ widget.controller.mapController.updateMapOptions(
new GoogleMapOptions(
- cameraTargetBounds: options.cameraTargetBounds.isBounded
- ? CameraTargetBounds.unbounded
- : const CameraTargetBounds(sydneyBounds),
+ latLngCameraTargetBounds:
+ _options.latLngCameraTargetBounds.bounds == null
+ ? const LatLngCameraTargetBounds(sydneyBounds)
+ : LatLngCameraTargetBounds.unbounded,
),
);
- _reloadOptions();
},
);
}
- Widget _zoomBoundsToggler(GoogleMapOptions options) {
+ Widget _zoomBoundsToggler() {
return new FlatButton(
- child: new Text(
- options.zoomBounds.isBounded ? 'release zoom' : 'bound zoom'),
- onPressed: () async {
- await widget.controller.mapsController.setMapOptions(
+ child: new Text(_options.minMaxZoomPreference.minZoom == null
+ ? 'bound zoom'
+ : 'release zoom'),
+ onPressed: () {
+ widget.controller.mapController.updateMapOptions(
new GoogleMapOptions(
- zoomBounds: options.zoomBounds.isBounded
- ? ZoomBounds.unbounded
- : const ZoomBounds(12.0, 16.0),
+ minMaxZoomPreference: _options.minMaxZoomPreference.minZoom == null
+ ? const MinMaxZoomPreference(12.0, 16.0)
+ : MinMaxZoomPreference.unbounded,
),
);
- _reloadOptions();
},
);
}
- Widget _mapTypeCycler(GoogleMapOptions options) {
+ Widget _mapTypeCycler() {
final MapType nextType =
- MapType.values[(options.mapType.index + 1) % MapType.values.length];
+ MapType.values[(_options.mapType.index + 1) % MapType.values.length];
return new FlatButton(
child: new Text('change map type to $nextType'),
- onPressed: () async {
- await widget.controller.mapsController.setMapOptions(
+ onPressed: () {
+ widget.controller.mapController.updateMapOptions(
new GoogleMapOptions(mapType: nextType),
);
- _reloadOptions();
},
);
}
- Widget _rotateToggler(GoogleMapOptions options) {
+ Widget _rotateToggler() {
return new FlatButton(
child: new Text(
- '${options.rotateGesturesEnabled ? 'disable' : 'enable'} rotate'),
- onPressed: () async {
- await widget.controller.mapsController.setMapOptions(
+ '${_options.rotateGesturesEnabled ? 'disable' : 'enable'} rotate'),
+ onPressed: () {
+ widget.controller.mapController.updateMapOptions(
new GoogleMapOptions(
- rotateGesturesEnabled: !options.rotateGesturesEnabled,
+ rotateGesturesEnabled: !_options.rotateGesturesEnabled,
),
);
- _reloadOptions();
},
);
}
- Widget _scrollToggler(GoogleMapOptions options) {
+ Widget _scrollToggler() {
return new FlatButton(
child: new Text(
- '${options.scrollGesturesEnabled ? 'disable' : 'enable'} scroll'),
- onPressed: () async {
- await widget.controller.mapsController.setMapOptions(
+ '${_options.scrollGesturesEnabled ? 'disable' : 'enable'} scroll'),
+ onPressed: () {
+ widget.controller.mapController.updateMapOptions(
new GoogleMapOptions(
- scrollGesturesEnabled: !options.scrollGesturesEnabled,
+ scrollGesturesEnabled: !_options.scrollGesturesEnabled,
),
);
- _reloadOptions();
},
);
}
- Widget _tiltToggler(GoogleMapOptions options) {
+ Widget _tiltToggler() {
return new FlatButton(
child: new Text(
- '${options.tiltGesturesEnabled ? 'disable' : 'enable'} tilt'),
- onPressed: () async {
- await widget.controller.mapsController.setMapOptions(
+ '${_options.tiltGesturesEnabled ? 'disable' : 'enable'} tilt'),
+ onPressed: () {
+ widget.controller.mapController.updateMapOptions(
new GoogleMapOptions(
- tiltGesturesEnabled: !options.tiltGesturesEnabled,
+ tiltGesturesEnabled: !_options.tiltGesturesEnabled,
),
);
- _reloadOptions();
},
);
}
- Widget _zoomToggler(GoogleMapOptions options) {
+ Widget _zoomToggler() {
return new FlatButton(
child: new Text(
- '${options.zoomGesturesEnabled ? 'disable' : 'enable'} zoom'),
- onPressed: () async {
- await widget.controller.mapsController.setMapOptions(
+ '${_options.zoomGesturesEnabled ? 'disable' : 'enable'} zoom'),
+ onPressed: () {
+ widget.controller.mapController.updateMapOptions(
new GoogleMapOptions(
- zoomGesturesEnabled: !options.zoomGesturesEnabled,
+ zoomGesturesEnabled: !_options.zoomGesturesEnabled,
),
);
- _reloadOptions();
},
);
}
- void _reloadOptions() {
- setState(() {
- _optionsFuture = widget.controller.mapsController.getMapOptions();
- });
- }
-
@override
Widget build(BuildContext context) {
return new Column(
@@ -194,35 +189,26 @@
new Padding(
padding: const EdgeInsets.all(10.0),
child: new Center(
- child: new GoogleMapsOverlay(controller: widget.controller),
+ child: new GoogleMapOverlay(controller: widget.controller),
),
),
- new FutureBuilder<GoogleMapOptions>(
- future: _optionsFuture,
- builder: (_, AsyncSnapshot<GoogleMapOptions> snapshot) {
- if (!snapshot.hasData) {
- return const Text('Loading settings');
- } else {
- final GoogleMapOptions options = snapshot.data;
- return new Column(
- children: <Widget>[
- new Text('camera bearing: ${options.cameraPosition.bearing}'),
- new Text(
- 'camera target: ${options.cameraPosition.target.latitude},${options.cameraPosition.target.longitude}'),
- new Text('camera zoom: ${options.cameraPosition.zoom}'),
- new Text('camera tilt: ${options.cameraPosition.tilt}'),
- _compassToggler(options),
- _latLngBoundsToggler(options),
- _mapTypeCycler(options),
- _zoomBoundsToggler(options),
- _rotateToggler(options),
- _scrollToggler(options),
- _tiltToggler(options),
- _zoomToggler(options),
- ],
- );
- }
- },
+ new Column(
+ children: <Widget>[
+ new Text('camera bearing: ${_position.bearing}'),
+ new Text(
+ 'camera target: ${_position.target.latitude.toStringAsFixed(4)},'
+ '${_position.target.longitude.toStringAsFixed(4)}'),
+ new Text('camera zoom: ${_position.zoom}'),
+ new Text('camera tilt: ${_position.tilt}'),
+ _compassToggler(),
+ _latLngBoundsToggler(),
+ _mapTypeCycler(),
+ _zoomBoundsToggler(),
+ _rotateToggler(),
+ _scrollToggler(),
+ _tiltToggler(),
+ _zoomToggler(),
+ ],
),
],
);
diff --git a/packages/google_mobile_maps/example/lib/move_camera.dart b/packages/google_mobile_maps/example/lib/move_camera.dart
index 4a396f9..209d2bb 100644
--- a/packages/google_mobile_maps/example/lib/move_camera.dart
+++ b/packages/google_mobile_maps/example/lib/move_camera.dart
@@ -10,12 +10,9 @@
class MoveCameraPage extends Page {
MoveCameraPage() : super(const Icon(Icons.map), "Camera control");
- final GoogleMapsOverlayController controller =
- new GoogleMapsOverlayController.fromSize(width: 300.0, height: 200.0);
-
@override
- PlatformOverlayController get overlayController =>
- controller.overlayController;
+ final GoogleMapOverlayController controller =
+ new GoogleMapOverlayController.fromSize(width: 300.0, height: 200.0);
@override
Widget build(BuildContext context) {
@@ -23,7 +20,7 @@
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
- new Center(child: new GoogleMapsOverlay(controller: controller)),
+ new Center(child: new GoogleMapOverlay(controller: controller)),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
@@ -31,7 +28,7 @@
children: <Widget>[
new FlatButton(
onPressed: () {
- controller.mapsController.moveCamera(
+ controller.mapController.moveCamera(
CameraUpdate.newCameraPosition(
const CameraPosition(
bearing: 270.0,
@@ -46,7 +43,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.moveCamera(
+ controller.mapController.moveCamera(
CameraUpdate.newLatLng(
const LatLng(56.1725505, 10.1850512),
),
@@ -56,7 +53,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.moveCamera(
+ controller.mapController.moveCamera(
CameraUpdate.newLatLngBounds(
const LatLngBounds(
southwest: const LatLng(-38.483935, 113.248673),
@@ -70,7 +67,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.moveCamera(
+ controller.mapController.moveCamera(
CameraUpdate.newLatLngZoom(
const LatLng(37.4231613, -122.087159),
11.0,
@@ -81,7 +78,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.moveCamera(
+ controller.mapController.moveCamera(
CameraUpdate.scrollBy(150.0, -225.0),
);
},
@@ -93,7 +90,7 @@
children: <Widget>[
new FlatButton(
onPressed: () {
- controller.mapsController.moveCamera(
+ controller.mapController.moveCamera(
CameraUpdate.zoomBy(
-0.5,
const Offset(30.0, 20.0),
@@ -104,7 +101,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.moveCamera(
+ controller.mapController.moveCamera(
CameraUpdate.zoomBy(-0.5),
);
},
@@ -112,7 +109,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.moveCamera(
+ controller.mapController.moveCamera(
CameraUpdate.zoomIn(),
);
},
@@ -120,7 +117,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.moveCamera(
+ controller.mapController.moveCamera(
CameraUpdate.zoomOut(),
);
},
@@ -128,7 +125,7 @@
),
new FlatButton(
onPressed: () {
- controller.mapsController.moveCamera(
+ controller.mapController.moveCamera(
CameraUpdate.zoomTo(16.0),
);
},
diff --git a/packages/google_mobile_maps/example/lib/page.dart b/packages/google_mobile_maps/example/lib/page.dart
index d47125d..0971918 100644
--- a/packages/google_mobile_maps/example/lib/page.dart
+++ b/packages/google_mobile_maps/example/lib/page.dart
@@ -11,5 +11,5 @@
final Widget leading;
final String title;
- PlatformOverlayController get overlayController;
+ GoogleMapOverlayController get controller;
}
diff --git a/packages/google_mobile_maps/example/lib/place_marker.dart b/packages/google_mobile_maps/example/lib/place_marker.dart
index 2bb5341..8551c3e 100644
--- a/packages/google_mobile_maps/example/lib/place_marker.dart
+++ b/packages/google_mobile_maps/example/lib/place_marker.dart
@@ -12,16 +12,18 @@
class PlaceMarkerPage extends Page {
PlaceMarkerPage() : super(const Icon(Icons.place), "Place marker");
- final GoogleMapsOverlayController controller =
- new GoogleMapsOverlayController.fromSize(width: 300.0, height: 200.0)
- ..mapsController.moveCamera(CameraUpdate.newLatLngZoom(
- const LatLng(-33.852, 151.211),
- 11.0,
- ));
-
@override
- PlatformOverlayController get overlayController =>
- controller.overlayController;
+ final GoogleMapOverlayController controller =
+ new GoogleMapOverlayController.fromSize(
+ width: 300.0,
+ height: 200.0,
+ options: const GoogleMapOptions(
+ cameraPosition: const CameraPosition(
+ target: const LatLng(-33.852, 151.211),
+ zoom: 11.0,
+ ),
+ ),
+ );
@override
Widget build(BuildContext context) {
@@ -30,7 +32,7 @@
}
class PlaceMarkerBody extends StatefulWidget {
- final GoogleMapsOverlayController controller;
+ final GoogleMapOverlayController controller;
const PlaceMarkerBody(this.controller);
@@ -41,151 +43,128 @@
class PlaceMarkerBodyState extends State<PlaceMarkerBody> {
static const LatLng center = const LatLng(-33.86711, 151.1947171);
- final List<Future<Marker>> markers = <Future<Marker>>[];
- int _nextAlpha = 1;
- int _nextHue = 1;
- int _nextPosition = 1;
- int _nextRotation = 1;
- int _nextAnchor = 1;
- int _nextInfoWindowAnchor = 7;
- int _nextTitle = 1;
- int _nextZIndex = 1;
+ int _markerCount = 0;
+ Marker _selectedMarker;
+
+ @override
+ void initState() {
+ super.initState();
+ widget.controller.mapController.onMarkerTapped.add((Marker marker) {
+ if (_selectedMarker != null) {
+ _selectedMarker
+ .update(const MarkerOptions(icon: BitmapDescriptor.defaultMarker));
+ }
+ setState(() {
+ _selectedMarker = marker;
+ });
+ _selectedMarker.update(new MarkerOptions(
+ icon: BitmapDescriptor
+ .defaultMarkerWithHue(BitmapDescriptor.hueGreen)));
+ });
+ }
void _add() {
+ widget.controller.mapController.addMarker(new MarkerOptions(
+ position: new LatLng(
+ center.latitude + sin(_markerCount * pi / 6.0) / 20.0,
+ center.longitude + cos(_markerCount * pi / 6.0) / 20.0,
+ ),
+ infoWindowText: new InfoWindowText('Marker #${_markerCount + 1}', '*'),
+ ));
setState(() {
- markers.add(
- widget.controller.mapsController.addMarker(
- new MarkerOptions(
- position: new LatLng(
- center.latitude + sin(markers.length * pi / 6.0) / 20.0,
- center.longitude + cos(markers.length * pi / 6.0) / 20.0,
- ),
- zIndex: markers.length.toDouble(),
- icon: BitmapDescriptor.defaultMarkerWithHue(30.0 * markers.length),
- ),
- ),
- );
+ _markerCount += 1;
});
}
- Future<void> _remove() async {
- final Marker marker = await markers.last;
+ void _remove() {
+ _selectedMarker.remove();
setState(() {
- markers.removeLast();
+ _selectedMarker = null;
+ _markerCount -= 1;
});
- await marker.remove();
}
- Future<void> _showInfo() async {
- final Marker marker = await markers.last;
- await marker.showInfoWindow();
- }
-
- Future<void> _hideInfo() async {
- final Marker marker = await markers.last;
- await marker.hideInfoWindow();
- }
-
- Future<void> _changePosition() async {
- final Marker marker = await markers.last;
- final LatLng position = new LatLng(
- center.latitude + sin(_nextPosition * pi / 6.0) / 20.0,
- center.longitude + cos(_nextPosition * pi / 6.0) / 20.0,
- );
- setState(() {
- _nextPosition = (_nextPosition + 1) % 12;
- });
- await marker.update(marker.options.copyWith(position: position));
- }
-
- Future<void> _changeAnchor() async {
- final Marker marker = await markers.last;
+ void _changePosition() {
+ final LatLng current = _selectedMarker.options.position;
final Offset offset = new Offset(
- (sin(_nextAnchor * pi / 6.0) + 1.0) / 2.0,
- (cos(_nextAnchor * pi / 6.0) + 1.0) / 2.0,
+ center.latitude - current.latitude,
+ center.longitude - current.longitude,
);
- setState(() {
- _nextAnchor = (_nextAnchor + 1) % 12;
- });
- await marker.update(marker.options.copyWith(anchor: offset));
+ _selectedMarker.update(
+ new MarkerOptions(
+ position: new LatLng(
+ center.latitude + offset.dy,
+ center.longitude + offset.dx,
+ ),
+ ),
+ );
+ }
+
+ void _changeAnchor() {
+ final Offset currentAnchor = _selectedMarker.options.anchor;
+ final Offset newAnchor =
+ new Offset(1.0 - currentAnchor.dy, currentAnchor.dx);
+ _selectedMarker.update(new MarkerOptions(anchor: newAnchor));
}
Future<void> _changeInfoAnchor() async {
- final Marker marker = await markers.last;
- final Offset offset = new Offset(
- (sin(_nextInfoWindowAnchor * pi / 6.0) + 1.0) / 2.0,
- (cos(_nextInfoWindowAnchor * pi / 6.0) + 1.0) / 2.0,
- );
- setState(() {
- _nextInfoWindowAnchor = (_nextInfoWindowAnchor + 1) % 12;
- });
- await marker.update(marker.options.copyWith(infoWindowAnchor: offset));
+ final Offset currentAnchor = _selectedMarker.options.infoWindowAnchor;
+ final Offset newAnchor =
+ new Offset(1.0 - currentAnchor.dy, currentAnchor.dx);
+ _selectedMarker.update(new MarkerOptions(infoWindowAnchor: newAnchor));
}
Future<void> _toggleDraggable() async {
- final Marker marker = await markers.last;
- await marker.update(
- marker.options.copyWith(draggable: !marker.options.draggable),
- );
+ _selectedMarker.update(
+ new MarkerOptions(draggable: !_selectedMarker.options.draggable));
}
Future<void> _toggleFlat() async {
- final Marker marker = await markers.last;
- await marker.update(
- marker.options.copyWith(flat: !marker.options.flat),
- );
+ _selectedMarker
+ .update(new MarkerOptions(flat: !_selectedMarker.options.flat));
}
Future<void> _changeInfo() async {
- final Marker marker = await markers.last;
- final String title = _nextTitle == 0 ? null : 'Title $_nextTitle';
- final String snippet = _nextTitle % 2 == 0 ? null : 'Snippet $_nextTitle';
- setState(() {
- _nextTitle = (_nextTitle + 1) % 12;
- });
- await marker.update(
- marker.options.copyWith(title: title, snippet: snippet),
- );
+ final InfoWindowText currentInfo = _selectedMarker.options.infoWindowText;
+ _selectedMarker.update(new MarkerOptions(
+ infoWindowText: new InfoWindowText(
+ currentInfo.title,
+ currentInfo.snippet + '*',
+ ),
+ ));
}
- Future<void> _changeIcon() async {
- final Marker marker = await markers.last;
- final BitmapDescriptor icon = BitmapDescriptor.defaultMarkerWithHue(
- _nextHue * 30.0,
+ Future<void> _toggleInfoShown() async {
+ _selectedMarker.update(
+ new MarkerOptions(
+ infoWindowShown: !_selectedMarker.options.infoWindowShown),
);
- setState(() {
- _nextHue = (_nextHue + 1) % 12;
- });
- await marker.update(marker.options.copyWith(icon: icon));
}
Future<void> _changeAlpha() async {
- final Marker marker = await markers.last;
- final double alpha = 1.0 - _nextAlpha / 12.0;
- setState(() {
- _nextAlpha = (_nextAlpha + 1) % 12;
- });
- await marker.update(marker.options.copyWith(alpha: alpha));
- }
-
- Future<void> _changeRotation() async {
- final Marker marker = await markers.last;
- final double rotation = _nextRotation * 30.0;
- setState(() {
- _nextRotation = (_nextRotation + 1) % 12;
- });
- await marker.update(
- marker.options.copyWith(rotation: rotation),
+ final double current = _selectedMarker.options.alpha;
+ _selectedMarker.update(
+ new MarkerOptions(alpha: current < 0.1 ? 1.0 : current * 0.75),
);
}
+ Future<void> _changeRotation() async {
+ final double current = _selectedMarker.options.rotation;
+ _selectedMarker.update(
+ new MarkerOptions(rotation: current == 330.0 ? 0.0 : current + 30.0),
+ );
+ }
+
+ Future<void> _toggleVisible() async {
+ _selectedMarker
+ .update(new MarkerOptions(visible: !_selectedMarker.options.visible));
+ }
+
Future<void> _changeZIndex() async {
- final Marker marker = await markers.last;
- final double zIndex = _nextZIndex.toDouble();
- setState(() {
- _nextZIndex = (_nextZIndex + 1) % 12;
- });
- await marker.update(marker.options.copyWith(zIndex: zIndex));
+ final double current = _selectedMarker.options.zIndex;
+ _selectedMarker.update(
+ new MarkerOptions(zIndex: current == 12.0 ? 0.0 : current + 1.0),
+ );
}
@override
@@ -194,7 +173,7 @@
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
- new Center(child: new GoogleMapsOverlay(controller: widget.controller)),
+ new Center(child: new GoogleMapOverlay(controller: widget.controller)),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
@@ -204,63 +183,68 @@
children: <Widget>[
new FlatButton(
child: const Text('add'),
- onPressed: (markers.length == 12) ? null : _add,
+ onPressed: (_markerCount == 12) ? null : _add,
),
new FlatButton(
child: const Text('remove'),
- onPressed: (markers.isEmpty) ? null : _remove,
+ onPressed: (_selectedMarker == null) ? null : _remove,
),
new FlatButton(
- child: const Text('show info'),
- onPressed: (markers.isEmpty) ? null : _showInfo,
+ child: const Text('change info'),
+ onPressed: (_selectedMarker == null) ? null : _changeInfo,
),
new FlatButton(
- child: const Text('hide info'),
- onPressed: (markers.isEmpty) ? null : _hideInfo,
+ child: const Text('change info anchor'),
+ onPressed:
+ (_selectedMarker == null) ? null : _changeInfoAnchor,
+ ),
+ new FlatButton(
+ child: const Text('toggle info shown'),
+ onPressed:
+ (_selectedMarker == null) ? null : _toggleInfoShown,
),
],
),
new Column(
children: <Widget>[
new FlatButton(
- child: const Text('change position'),
- onPressed: (markers.isEmpty) ? null : _changePosition,
+ child: const Text('change alpha'),
+ onPressed:
+ (_selectedMarker == null) ? null : _changeAlpha,
),
new FlatButton(
child: const Text('change anchor'),
- onPressed: (markers.isEmpty) ? null : _changeAnchor,
- ),
- new FlatButton(
- child: const Text('change info anchor'),
- onPressed: (markers.isEmpty) ? null : _changeInfoAnchor,
+ onPressed:
+ (_selectedMarker == null) ? null : _changeAnchor,
),
new FlatButton(
child: const Text('toggle draggable'),
- onPressed: (markers.isEmpty) ? null : _toggleDraggable,
+ onPressed:
+ (_selectedMarker == null) ? null : _toggleDraggable,
),
new FlatButton(
child: const Text('toggle flat'),
- onPressed: (markers.isEmpty) ? null : _toggleFlat,
+ onPressed: (_selectedMarker == null) ? null : _toggleFlat,
),
new FlatButton(
- child: const Text('change info'),
- onPressed: (markers.isEmpty) ? null : _changeInfo,
- ),
- new FlatButton(
- child: const Text('change color'),
- onPressed: (markers.isEmpty) ? null : _changeIcon,
- ),
- new FlatButton(
- child: const Text('change alpha'),
- onPressed: (markers.isEmpty) ? null : _changeAlpha,
+ child: const Text('change position'),
+ onPressed:
+ (_selectedMarker == null) ? null : _changePosition,
),
new FlatButton(
child: const Text('change rotation'),
- onPressed: (markers.isEmpty) ? null : _changeRotation,
+ onPressed:
+ (_selectedMarker == null) ? null : _changeRotation,
+ ),
+ new FlatButton(
+ child: const Text('toggle visible'),
+ onPressed:
+ (_selectedMarker == null) ? null : _toggleVisible,
),
new FlatButton(
child: const Text('change zIndex'),
- onPressed: (markers.isEmpty) ? null : _changeZIndex,
+ onPressed:
+ (_selectedMarker == null) ? null : _changeZIndex,
),
],
),
diff --git a/packages/google_mobile_maps/lib/google_mobile_maps.dart b/packages/google_mobile_maps/lib/google_mobile_maps.dart
index 2b12899..a58533e 100644
--- a/packages/google_mobile_maps/lib/google_mobile_maps.dart
+++ b/packages/google_mobile_maps/lib/google_mobile_maps.dart
@@ -15,6 +15,7 @@
export 'dart:async';
part 'src/bitmap.dart';
+part 'src/callbacks.dart';
part 'src/camera.dart';
part 'src/controller.dart';
part 'src/ui.dart';
diff --git a/packages/google_mobile_maps/lib/src/callbacks.dart b/packages/google_mobile_maps/lib/src/callbacks.dart
new file mode 100644
index 0000000..82a9abe
--- /dev/null
+++ b/packages/google_mobile_maps/lib/src/callbacks.dart
@@ -0,0 +1,44 @@
+// 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.
+
+part of google_mobile_maps;
+
+/// Callback function taking a single argument.
+typedef void ArgumentCallback<T>(T argument);
+
+/// Mutable collection of [ArgumentCallback] instances, itself an [ArgumentCallback].
+///
+/// Additions and removals happening during a single [call] invocation do not
+/// change who gets a callback until the next such invocation.
+class ArgumentCallbacks<T> {
+ final List<ArgumentCallback<T>> _callbacks = <ArgumentCallback<T>>[];
+ VoidCallback _onEmptyChanged;
+
+ void call(T argument) {
+ final int length = _callbacks.length;
+ if (length == 1) {
+ _callbacks[0].call(argument);
+ } else if (0 < length) {
+ for (ArgumentCallback<T> callback
+ in new List<ArgumentCallback<T>>.from(_callbacks)) {
+ callback(argument);
+ }
+ }
+ }
+
+ void add(ArgumentCallback<T> callback) {
+ _callbacks.add(callback);
+ if (_onEmptyChanged != null && _callbacks.length == 1) _onEmptyChanged();
+ }
+
+ void remove(ArgumentCallback<T> callback) {
+ final bool removed = _callbacks.remove(callback);
+ if (_onEmptyChanged != null && removed && _callbacks.isEmpty)
+ _onEmptyChanged();
+ }
+
+ bool get isEmpty => _callbacks.isEmpty;
+
+ bool get isNotEmpty => _callbacks.isNotEmpty;
+}
diff --git a/packages/google_mobile_maps/lib/src/controller.dart b/packages/google_mobile_maps/lib/src/controller.dart
index 779d65e..a291840 100644
--- a/packages/google_mobile_maps/lib/src/controller.dart
+++ b/packages/google_mobile_maps/lib/src/controller.dart
@@ -7,35 +7,107 @@
final MethodChannel _channel =
const MethodChannel('plugins.flutter.io/google_mobile_maps');
-/// Controller for a single GoogleMaps instance.
+/// Controller for a single GoogleMap instance.
///
-/// Used for programmatically controlling a platform-specific
-/// GoogleMaps view, once created.
-class GoogleMapsController {
+/// Used for programmatically controlling a platform-specific GoogleMap view.
+///
+/// Change listeners are notified upon changes to any of
+///
+/// * the [options] property,
+/// * the collection of [Marker]s added to this map
+/// * the [cameraPosition] property,
+///
+/// Listeners are notified when changes have been applied on the platform side.
+///
+/// Marker tap events can be received by adding callbacks to [onMarkerTapped].
+class GoogleMapController extends ChangeNotifier {
+ GoogleMapController._({
+ this.id,
+ GoogleMapOptions options,
+ }) : _options = options {
+ id.then((int id) {
+ _controllers[id] = this;
+ });
+ if (options.trackCameraPosition) {
+ _cameraPosition = options.cameraPosition;
+ }
+ }
+
/// An ID identifying the GoogleMaps instance, once created.
final Future<int> id;
- GoogleMapsController(this.id);
+ final ArgumentCallbacks<Marker> onMarkerTapped =
+ new ArgumentCallbacks<Marker>();
+
+ /// The configuration options most recently applied via controller
+ /// initialization or [updateMapOptions].
+ GoogleMapOptions get options => _options;
+ GoogleMapOptions _options;
+
+ Set<Marker> get markers => new Set<Marker>.from(_markers.values);
+ final Map<String, Marker> _markers = <String, Marker>{};
+
+ bool get isCameraMoving => _isCameraMoving;
+ bool _isCameraMoving = false;
+
+ /// Returns the most recent camera position reported by the platform side.
+ /// Will be null, if camera position tracking is not enabled via
+ /// [GoogleMapOptions].
+ CameraPosition get cameraPosition => _cameraPosition;
+ CameraPosition _cameraPosition;
+
+ static Map<int, GoogleMapController> _controllers =
+ <int, GoogleMapController>{};
static Future<void> init() async {
await _channel.invokeMethod('init');
+ _channel.setMethodCallHandler((MethodCall call) {
+ final int mapId = call.arguments['map'];
+ final GoogleMapController controller = _controllers[mapId];
+ if (controller != null) {
+ controller._handleMethodCall(call);
+ }
+ });
}
- Future<void> setMapOptions(GoogleMapOptions options) async {
+ void _handleMethodCall(MethodCall call) {
+ switch (call.method) {
+ case "marker#onTap":
+ final String markerId = call.arguments['marker'];
+ final Marker marker = _markers[markerId];
+ if (marker != null) {
+ onMarkerTapped(marker);
+ }
+ break;
+ case "map#onCameraMoveStarted":
+ _isCameraMoving = true;
+ notifyListeners();
+ break;
+ case "map#onCameraMove":
+ _cameraPosition = CameraPosition._fromJson(call.arguments['position']);
+ notifyListeners();
+ break;
+ case "map#onCameraIdle":
+ _isCameraMoving = false;
+ notifyListeners();
+ break;
+ default:
+ throw new MissingPluginException();
+ }
+ }
+
+ Future<void> updateMapOptions(GoogleMapOptions options) async {
+ assert(options != null);
final int id = await this.id;
await _channel.invokeMethod('setMapOptions', <String, dynamic>{
'map': id,
'options': options._toJson(),
});
- }
-
- Future<GoogleMapOptions> getMapOptions() async {
- final int id = await this.id;
- final dynamic json = await _channel.invokeMethod(
- 'getMapOptions',
- <String, dynamic>{'map': id},
- );
- return GoogleMapOptions._fromJson(json);
+ _options = _options._updateWith(options);
+ if (!_options.trackCameraPosition) {
+ _cameraPosition = null;
+ }
+ notifyListeners();
}
Future<void> animateCamera(CameraUpdate cameraUpdate) async {
@@ -54,31 +126,62 @@
});
}
- Future<Marker> addMarker(MarkerOptions markerOptions) async {
+ Future<Marker> addMarker(MarkerOptions options) async {
+ assert(options != null);
+ assert(options.position != null);
final int id = await this.id;
+ final MarkerOptions effectiveOptions =
+ MarkerOptions.defaultOptions._updateWith(options);
final String markerId = await _channel.invokeMethod(
'addMarker',
<String, dynamic>{
'map': id,
- 'markerOptions': markerOptions._toJson(),
+ 'options': effectiveOptions._toJson(),
},
);
- return new Marker._(id, markerId, markerOptions);
+ final Marker marker = new Marker._(this, markerId, effectiveOptions);
+ _markers[markerId] = marker;
+ notifyListeners();
+ return marker;
+ }
+
+ Future<void> _updateMarker(Marker marker, MarkerOptions changes) async {
+ assert(_markers[marker.id] == marker);
+ assert(changes != null);
+ final int id = await this.id;
+ await _channel.invokeMethod('marker#update', <String, dynamic>{
+ 'map': id,
+ 'marker': marker.id,
+ 'options': changes._toJson(),
+ });
+ marker._options = marker._options._updateWith(changes);
+ notifyListeners();
+ }
+
+ Future<void> _removeMarker(Marker marker) async {
+ assert(_markers[marker.id] == marker);
+ final int id = await this.id;
+ await _channel.invokeMethod('marker#remove', <String, dynamic>{
+ 'map': id,
+ 'marker': marker.id,
+ });
+ _markers.remove(marker.id);
+ notifyListeners();
}
}
-/// Controller for a GoogleMaps instance that is integrated as a
+/// Controller for a GoogleMap instance that is integrated as a
/// platform overlay.
///
/// *Warning*: Platform overlays cannot be freely composed with
/// other widgets. See [PlatformOverlayController] for caveats and
/// limitations.
-class GoogleMapsOverlayController {
- GoogleMapsOverlayController._(this.mapsController, this.overlayController);
+class GoogleMapOverlayController {
+ GoogleMapOverlayController._(this.mapController, this.overlayController);
/// Creates a controller for a GoogleMaps of the specified size in
/// logical pixels.
- factory GoogleMapsOverlayController.fromSize({
+ factory GoogleMapOverlayController.fromSize({
@required double width,
@required double height,
GoogleMapOptions options = const GoogleMapOptions(),
@@ -86,16 +189,21 @@
assert(width != null);
assert(height != null);
assert(options != null);
+ final GoogleMapOptions effectiveOptions =
+ GoogleMapOptions.defaultOptions._updateWith(options);
final _GoogleMapsPlatformOverlay overlay =
- new _GoogleMapsPlatformOverlay(options);
- return new GoogleMapsOverlayController._(
- new GoogleMapsController(overlay._textureId.future),
+ new _GoogleMapsPlatformOverlay(effectiveOptions);
+ return new GoogleMapOverlayController._(
+ new GoogleMapController._(
+ id: overlay._textureId.future,
+ options: effectiveOptions,
+ ),
new PlatformOverlayController(width, height, overlay),
);
}
/// The controller of the GoogleMaps instance.
- final GoogleMapsController mapsController;
+ final GoogleMapController mapController;
/// The controller of the platform overlay.
final PlatformOverlayController overlayController;
@@ -149,16 +257,16 @@
}
/// A Widget covered by a GoogleMaps platform overlay.
-class GoogleMapsOverlay extends StatefulWidget {
- final GoogleMapsOverlayController controller;
+class GoogleMapOverlay extends StatefulWidget {
+ final GoogleMapOverlayController controller;
- GoogleMapsOverlay({Key key, @required this.controller}) : super(key: key);
+ GoogleMapOverlay({Key key, @required this.controller}) : super(key: key);
@override
- State<StatefulWidget> createState() => new _GoogleMapsOverlayState();
+ State<StatefulWidget> createState() => new _GoogleMapOverlayState();
}
-class _GoogleMapsOverlayState extends State<GoogleMapsOverlay> {
+class _GoogleMapOverlayState extends State<GoogleMapOverlay> {
@override
void initState() {
super.initState();
@@ -175,7 +283,7 @@
Widget build(BuildContext context) {
return new SizedBox(
child: new FutureBuilder<int>(
- future: widget.controller.mapsController.id,
+ future: widget.controller.mapController.id,
builder: (_, AsyncSnapshot<int> snapshot) {
if (snapshot.hasData) {
return new Texture(textureId: snapshot.data);
diff --git a/packages/google_mobile_maps/lib/src/marker.dart b/packages/google_mobile_maps/lib/src/marker.dart
index 14b9b91..a328978 100644
--- a/packages/google_mobile_maps/lib/src/marker.dart
+++ b/packages/google_mobile_maps/lib/src/marker.dart
@@ -4,127 +4,134 @@
part of google_mobile_maps;
+/// An icon placed at a particular point on the map's surface. A marker icon is
+/// drawn oriented against the device's screen rather than the map's surface;
+/// that is, it will not necessarily change orientation due to map rotations,
+/// tilting, or zooming.
+///
+/// Markers are owned by a single [GoogleMapController] which fires change
+/// events when markers are added, updated, or removed.
class Marker {
- Marker._(this.mapId, this.id, MarkerOptions options) : _options = options;
+ Marker._(this._mapController, this.id, this._options);
- final int mapId;
+ final GoogleMapController _mapController;
final String id;
MarkerOptions _options;
- Future<void> update(MarkerOptions options) async {
- assert(options != null);
- _options = options;
- await _channel.invokeMethod('marker#update', <String, dynamic>{
- 'map': mapId,
- 'marker': id,
- 'markerOptions': options._toJson(),
- });
+ Future<void> remove() {
+ return _mapController._removeMarker(this);
}
+ Future<void> update(MarkerOptions changes) {
+ return _mapController._updateMarker(this, changes);
+ }
+
+ /// The configuration options most recently applied programmatically.
+ ///
+ /// The returned value does not reflect any changes made to the marker through
+ /// touch events. Add listeners to track those.
MarkerOptions get options => _options;
-
- Future<void> remove() async {
- await _channel.invokeMethod('marker#remove', <String, dynamic>{
- 'map': mapId,
- 'marker': id,
- });
- }
-
- Future<void> hideInfoWindow() async {
- await _channel.invokeMethod('marker#hideInfoWindow', <String, dynamic>{
- 'map': mapId,
- 'marker': id,
- });
- }
-
- Future<void> showInfoWindow() async {
- await _channel.invokeMethod('marker#showInfoWindow', <String, dynamic>{
- 'map': mapId,
- 'marker': id,
- });
- }
}
+dynamic _offsetToJson(Offset offset) =>
+ offset == null ? null : <dynamic>[offset.dx, offset.dy];
+
+/// Text labels for a [Marker] info window.
+class InfoWindowText {
+ const InfoWindowText(this.title, this.snippet);
+
+ static const InfoWindowText noText = const InfoWindowText(null, null);
+
+ final String title;
+ final String snippet;
+
+ dynamic _toJson() => <dynamic>[title, snippet];
+}
+
+/// 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.
class MarkerOptions {
- static const String unspecified = 'Unspecified';
- final LatLng position;
final double alpha;
final Offset anchor;
+ final bool consumesTapEvents;
final bool draggable;
final bool flat;
final BitmapDescriptor icon;
final Offset infoWindowAnchor;
+ final bool infoWindowShown;
+ final InfoWindowText infoWindowText;
+ final LatLng position;
final double rotation;
- final String snippet;
- final String title;
final bool visible;
final double zIndex;
const MarkerOptions({
- @required this.position,
- this.alpha = 1.0,
- this.anchor = const Offset(0.5, 1.0),
- this.draggable = false,
- this.flat = false,
- this.icon = BitmapDescriptor.defaultMarker,
- this.infoWindowAnchor = const Offset(0.5, 0.0),
- this.rotation = 0.0,
- this.snippet,
- this.title,
- this.visible = true,
- this.zIndex = 0.0,
- }) : assert(position != null),
- assert(alpha != null),
- assert(anchor != null),
- assert(draggable != null),
- assert(flat != null),
- assert(icon != null),
- assert(infoWindowAnchor != null),
- assert(rotation != null),
- assert(zIndex != null),
- assert(visible != null);
+ this.alpha,
+ this.anchor,
+ this.consumesTapEvents,
+ this.draggable,
+ this.flat,
+ this.icon,
+ this.infoWindowAnchor,
+ this.infoWindowShown,
+ this.infoWindowText,
+ this.position,
+ this.rotation,
+ this.visible,
+ this.zIndex,
+ });
- MarkerOptions copyWith({
- LatLng position,
- double alpha,
- Offset anchor,
- bool draggable,
- bool flat,
- BitmapDescriptor icon,
- Offset infoWindowAnchor,
- double rotation,
- String snippet = unspecified,
- String title = unspecified,
- double zIndex,
- bool visible,
- }) =>
- new MarkerOptions(
- position: position ?? this.position,
- alpha: alpha ?? this.alpha,
- anchor: anchor ?? this.anchor,
- draggable: draggable ?? this.draggable,
- flat: flat ?? this.flat,
- icon: icon ?? this.icon,
- infoWindowAnchor: infoWindowAnchor ?? this.infoWindowAnchor,
- rotation: rotation ?? this.rotation,
- snippet: identical(snippet, unspecified) ? this.snippet : snippet,
- title: identical(title, unspecified) ? this.title : title,
- zIndex: zIndex ?? this.zIndex,
- visible: visible ?? this.visible,
- );
+ static const MarkerOptions defaultOptions = const MarkerOptions(
+ alpha: 1.0,
+ anchor: const Offset(0.5, 1.0),
+ consumesTapEvents: 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,
+ zIndex: 0.0,
+ );
- dynamic _toJson() => <String, dynamic>{
- 'position': position._toJson(),
- 'alpha': alpha,
- 'anchor': <double>[anchor.dx, anchor.dy],
- 'draggable': draggable,
- 'flat': flat,
- 'icon': icon._toJson(),
- 'infoWindowAnchor': <double>[infoWindowAnchor.dx, infoWindowAnchor.dy],
- 'rotation': rotation,
- 'snippet': snippet,
- 'title': title,
- 'visible': visible,
- 'zIndex': zIndex,
- };
+ MarkerOptions _updateWith(MarkerOptions changes) {
+ return new MarkerOptions(
+ alpha: changes.alpha ?? alpha,
+ anchor: changes.anchor ?? anchor,
+ consumesTapEvents: changes.consumesTapEvents ?? consumesTapEvents,
+ 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,
+ visible: changes.visible ?? visible,
+ zIndex: changes.zIndex ?? zIndex,
+ );
+ }
+
+ 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,
+ };
+ }
}
diff --git a/packages/google_mobile_maps/lib/src/platform_overlay.dart b/packages/google_mobile_maps/lib/src/platform_overlay.dart
index 8baff43..067fd67 100644
--- a/packages/google_mobile_maps/lib/src/platform_overlay.dart
+++ b/packages/google_mobile_maps/lib/src/platform_overlay.dart
@@ -4,7 +4,7 @@
part of google_mobile_maps;
-/// Controller of platform overlays, supporting a limited form
+/// Controller of platform overlays, supporting a very limited form
/// of compositing with Flutter Widgets.
///
/// Platform overlays are normal platform-specific views that are
@@ -207,19 +207,19 @@
/// Platform overlay.
abstract class PlatformOverlay {
- /// Create a platform view of the specified [physicalSize] (in device pixels).
+ /// Creates a platform view of the specified [physicalSize] (in device pixels).
///
/// The platform view should remain hidden until explicitly shown by calling
/// [showOverlay].
Future<int> create(Size physicalSize);
- /// Show the platform view at the specified [physicalOffset] (in device
+ /// Shows the platform view at the specified [physicalOffset] (in device
/// pixels).
Future<void> show(Offset physicalOffset);
- /// Hide the platform view.
+ /// Hides the platform view.
Future<void> hide();
- /// Dispose of the platform view.
+ /// Disposes of the platform view.
Future<void> dispose();
}
diff --git a/packages/google_mobile_maps/lib/src/ui.dart b/packages/google_mobile_maps/lib/src/ui.dart
index b86744c..1323136 100644
--- a/packages/google_mobile_maps/lib/src/ui.dart
+++ b/packages/google_mobile_maps/lib/src/ui.dart
@@ -17,39 +17,22 @@
hybrid,
}
-MapType _mapTypeFromJson(dynamic json) {
- if (json == null) {
- return null;
- }
- return MapType.values[json];
-}
-
/// Bounds for the map camera target.
-class CameraTargetBounds {
- static const CameraTargetBounds unbounded = const CameraTargetBounds(null);
-
- const CameraTargetBounds(this.bounds);
+class LatLngCameraTargetBounds {
+ const LatLngCameraTargetBounds(this.bounds);
/// The current bounds or null, if the camera target is unbounded.
final LatLngBounds bounds;
- bool get isBounded => bounds != null;
+ static const LatLngCameraTargetBounds unbounded =
+ const LatLngCameraTargetBounds(null);
dynamic _toJson() => <dynamic>[bounds?._toJson()];
-
- static CameraTargetBounds _fromJson(dynamic json) {
- if (json == null) {
- return null;
- }
- return new CameraTargetBounds(LatLngBounds._fromJson(json[0]));
- }
}
-/// Bounds for map camera zoom level.
-class ZoomBounds {
- static const ZoomBounds unbounded = const ZoomBounds(null, null);
-
- const ZoomBounds(this.minZoom, this.maxZoom)
+/// Preferred bounds for map camera zoom level.
+class MinMaxZoomPreference {
+ const MinMaxZoomPreference(this.minZoom, this.maxZoom)
: assert(minZoom == null || maxZoom == null || minZoom <= maxZoom);
/// The current minimum zoom level or null, if unbounded from below.
@@ -58,16 +41,10 @@
/// The current maximum zoom level or null, if unbounded from above.
final double maxZoom;
- bool get isBounded => minZoom != null || maxZoom != null;
+ static const MinMaxZoomPreference unbounded =
+ const MinMaxZoomPreference(null, null);
dynamic _toJson() => <dynamic>[minZoom, maxZoom];
-
- static ZoomBounds _fromJson(dynamic json) {
- if (json == null) {
- return null;
- }
- return new ZoomBounds(json[0], json[1]);
- }
}
/// Configuration options for the GoogleMaps user interface.
@@ -77,55 +54,71 @@
/// configuration, all values will be non-null.
class GoogleMapOptions {
final CameraPosition cameraPosition;
- final CameraTargetBounds cameraTargetBounds;
final bool compassEnabled;
+ final LatLngCameraTargetBounds latLngCameraTargetBounds;
final MapType mapType;
+ final MinMaxZoomPreference minMaxZoomPreference;
final bool rotateGesturesEnabled;
final bool scrollGesturesEnabled;
final bool tiltGesturesEnabled;
- final ZoomBounds zoomBounds;
+ final bool trackCameraPosition;
final bool zoomGesturesEnabled;
const GoogleMapOptions({
this.cameraPosition,
- this.cameraTargetBounds,
this.compassEnabled,
+ this.latLngCameraTargetBounds,
this.mapType,
+ this.minMaxZoomPreference,
this.rotateGesturesEnabled,
this.scrollGesturesEnabled,
this.tiltGesturesEnabled,
- this.zoomBounds,
+ this.trackCameraPosition,
this.zoomGesturesEnabled,
});
- static GoogleMapOptions _fromJson(dynamic json) {
- if (json == null) {
- return null;
- }
+ static const GoogleMapOptions defaultOptions = const GoogleMapOptions(
+ compassEnabled: true,
+ latLngCameraTargetBounds: LatLngCameraTargetBounds.unbounded,
+ mapType: MapType.normal,
+ minMaxZoomPreference: MinMaxZoomPreference.unbounded,
+ rotateGesturesEnabled: true,
+ scrollGesturesEnabled: true,
+ tiltGesturesEnabled: true,
+ trackCameraPosition: false,
+ zoomGesturesEnabled: true,
+ );
+
+ GoogleMapOptions _updateWith(GoogleMapOptions change) {
return new GoogleMapOptions(
- cameraPosition: CameraPosition._fromJson(json['cameraPosition']),
- cameraTargetBounds:
- CameraTargetBounds._fromJson(json['cameraTargetBounds']),
- compassEnabled: json['compassEnabled'],
- mapType: _mapTypeFromJson(json['mapType']),
- rotateGesturesEnabled: json['rotateGesturesEnabled'],
- scrollGesturesEnabled: json['scrollGesturesEnabled'],
- tiltGesturesEnabled: json['tiltGesturesEnabled'],
- zoomBounds: ZoomBounds._fromJson(json['zoomBounds']),
- zoomGesturesEnabled: json['zoomGesturesEnabled'],
+ cameraPosition: change.cameraPosition ?? cameraPosition,
+ compassEnabled: change.compassEnabled ?? compassEnabled,
+ latLngCameraTargetBounds:
+ change.latLngCameraTargetBounds ?? latLngCameraTargetBounds,
+ mapType: change.mapType ?? mapType,
+ minMaxZoomPreference: change.minMaxZoomPreference ?? minMaxZoomPreference,
+ rotateGesturesEnabled:
+ change.rotateGesturesEnabled ?? rotateGesturesEnabled,
+ scrollGesturesEnabled:
+ change.scrollGesturesEnabled ?? scrollGesturesEnabled,
+ tiltGesturesEnabled: change.tiltGesturesEnabled ?? tiltGesturesEnabled,
+ trackCameraPosition: change.trackCameraPosition ?? trackCameraPosition,
+ zoomGesturesEnabled: change.zoomGesturesEnabled ?? zoomGesturesEnabled,
);
}
dynamic _toJson() {
final Map<String, dynamic> json = <String, dynamic>{};
json['cameraPosition'] = cameraPosition?._toJson();
- json['cameraTargetBounds'] = cameraTargetBounds?._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['zoomBounds'] = zoomBounds?._toJson();
+ json['trackCameraPosition'] = trackCameraPosition;
json['zoomGesturesEnabled'] = zoomGesturesEnabled;
return json;
}