[google_maps_flutter] Fix the visual jarring during the first gesture on the map (#2629)
diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
index 5b3e350..bdc8a73 100644
--- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
+++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.5.26+3
+
+* iOS: observe the bounds update for the `GMSMapView` to reset the camera setting.
+* Update UI related e2e tests to wait for camera update on the platform thread.
+
## 0.5.26+2
* Fix UIKit availability warnings and CocoaPods podspec lint warnings.
diff --git a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/google_maps_e2e.dart b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/google_maps_e2e.dart
index 3b78d2f..2eccbc4 100644
--- a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/google_maps_e2e.dart
+++ b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/google_maps_e2e.dart
@@ -383,6 +383,53 @@
expect(scrollGesturesEnabled, true);
});
+ testWidgets('testInitialCenterLocationAtCenter', (WidgetTester tester) async {
+ final Completer<GoogleMapController> mapControllerCompleter =
+ Completer<GoogleMapController>();
+ final Key key = GlobalKey();
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.ltr,
+ child: GoogleMap(
+ key: key,
+ initialCameraPosition: _kInitialCameraPosition,
+ onMapCreated: (GoogleMapController controller) {
+ mapControllerCompleter.complete(controller);
+ },
+ ),
+ ),
+ );
+ final GoogleMapController mapController =
+ await mapControllerCompleter.future;
+
+ await tester.pumpAndSettle();
+ // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen
+ // in `mapRendered`.
+ // https://github.com/flutter/flutter/issues/54758
+ await Future.delayed(Duration(seconds: 1));
+
+ ScreenCoordinate coordinate =
+ await mapController.getScreenCoordinate(_kInitialCameraPosition.target);
+ Rect rect = tester.getRect(find.byKey(key));
+ if (Platform.isIOS) {
+ // On iOS, the coordinate value from the GoogleMapSdk doesn't include the devicePixelRatio`.
+ // So we don't need to do the conversion like we did below for other platforms.
+ expect(coordinate.x, (rect.center.dx - rect.topLeft.dx).round());
+ expect(coordinate.y, (rect.center.dy - rect.topLeft.dy).round());
+ } else {
+ expect(
+ coordinate.x,
+ ((rect.center.dx - rect.topLeft.dx) *
+ tester.binding.window.devicePixelRatio)
+ .round());
+ expect(
+ coordinate.y,
+ ((rect.center.dy - rect.topLeft.dy) *
+ tester.binding.window.devicePixelRatio)
+ .round());
+ }
+ });
+
testWidgets('testGetVisibleRegion', (WidgetTester tester) async {
final Key key = GlobalKey();
final LatLngBounds zeroLatLngBounds = LatLngBounds(
@@ -401,13 +448,8 @@
},
),
));
- // We suspected a bug in the iOS Google Maps SDK caused the camera is not properly positioned at
- // initialization. https://github.com/flutter/flutter/issues/24806
- // This temporary workaround fix is provided while the actual fix in the Google Maps SDK is
- // still being investigated.
- // TODO(cyanglaz): Remove this temporary fix once the Maps SDK issue is resolved.
- // https://github.com/flutter/flutter/issues/27550
- await tester.pumpAndSettle(const Duration(seconds: 3));
+ await tester.pumpAndSettle();
+
final GoogleMapController mapController =
await mapControllerCompleter.future;
@@ -707,13 +749,11 @@
final GoogleMapController controller = await controllerCompleter.future;
- // We suspected a bug in the iOS Google Maps SDK caused the camera is not properly positioned at
- // initialization. https://github.com/flutter/flutter/issues/24806
- // This temporary workaround fix is provided while the actual fix in the Google Maps SDK is
- // still being investigated.
- // TODO(cyanglaz): Remove this temporary fix once the Maps SDK issue is resolved.
- // https://github.com/flutter/flutter/issues/27550
- await tester.pumpAndSettle(const Duration(seconds: 3));
+ await tester.pumpAndSettle();
+ // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen
+ // in `mapRendered`.
+ // https://github.com/flutter/flutter/issues/54758
+ await Future.delayed(Duration(seconds: 1));
final LatLngBounds visibleRegion = await controller.getVisibleRegion();
final LatLng topLeft =
@@ -744,13 +784,11 @@
final GoogleMapController controller = await controllerCompleter.future;
- // We suspected a bug in the iOS Google Maps SDK caused the camera is not properly positioned at
- // initialization. https://github.com/flutter/flutter/issues/24806
- // This temporary workaround fix is provided while the actual fix in the Google Maps SDK is
- // still being investigated.
- // TODO(cyanglaz): Remove this temporary fix once the Maps SDK issue is resolved.
- // https://github.com/flutter/flutter/issues/27550
- await tester.pumpAndSettle(const Duration(seconds: 3));
+ await tester.pumpAndSettle();
+ // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen
+ // in `mapRendered`.
+ // https://github.com/flutter/flutter/issues/54758
+ await Future.delayed(Duration(seconds: 1));
double zoom = await controller.getZoomLevel();
expect(zoom, _kInitialZoomLevel);
@@ -778,13 +816,11 @@
));
final GoogleMapController controller = await controllerCompleter.future;
- // We suspected a bug in the iOS Google Maps SDK caused the camera is not properly positioned at
- // initialization. https://github.com/flutter/flutter/issues/24806
- // This temporary workaround fix is provided while the actual fix in the Google Maps SDK is
- // still being investigated.
- // TODO(cyanglaz): Remove this temporary fix once the Maps SDK issue is resolved.
- // https://github.com/flutter/flutter/issues/27550
- await tester.pumpAndSettle(const Duration(seconds: 3));
+ await tester.pumpAndSettle();
+ // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen
+ // in `mapRendered`.
+ // https://github.com/flutter/flutter/issues/54758
+ await Future.delayed(Duration(seconds: 1));
final LatLngBounds visibleRegion = await controller.getVisibleRegion();
final LatLng northWest = LatLng(
@@ -818,13 +854,11 @@
home: Scaffold(
body: SizedBox(height: 400, width: 400, child: map)))));
- // We suspected a bug in the iOS Google Maps SDK caused the camera is not properly positioned at
- // initialization. https://github.com/flutter/flutter/issues/24806
- // This temporary workaround fix is provided while the actual fix in the Google Maps SDK is
- // still being investigated.
- // TODO(cyanglaz): Remove this temporary fix once the Maps SDK issue is resolved.
- // https://github.com/flutter/flutter/issues/27550
- await tester.pumpAndSettle(const Duration(seconds: 3));
+ await tester.pumpAndSettle();
+ // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen
+ // in `mapRendered`.
+ // https://github.com/flutter/flutter/issues/54758
+ await Future.delayed(Duration(seconds: 1));
// Simple call to make sure that the app hasn't crashed.
final LatLngBounds bounds1 = await controller.getVisibleRegion();
diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m
index 59bfaa0..321ddd3 100644
--- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m
+++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m
@@ -50,10 +50,6 @@
FlutterMethodChannel* _channel;
BOOL _trackCameraPosition;
NSObject<FlutterPluginRegistrar>* _registrar;
- // Used for the temporary workaround for a bug that the camera is not properly positioned at
- // initialization. https://github.com/flutter/flutter/issues/24806
- // TODO(cyanglaz): Remove this temporary fix once the Maps SDK issue is resolved.
- // https://github.com/flutter/flutter/issues/27550
BOOL _cameraDidInitialSetup;
FLTMarkersController* _markersController;
FLTPolygonsController* _polygonsController;
@@ -119,9 +115,36 @@
}
- (UIView*)view {
+ [_mapView addObserver:self forKeyPath:@"frame" options:0 context:nil];
return _mapView;
}
+- (void)observeValueForKeyPath:(NSString*)keyPath
+ ofObject:(id)object
+ change:(NSDictionary*)change
+ context:(void*)context {
+ if (_cameraDidInitialSetup) {
+ // We only observe the frame for initial setup.
+ [_mapView removeObserver:self forKeyPath:@"frame"];
+ return;
+ }
+ if (object == _mapView && [keyPath isEqualToString:@"frame"]) {
+ CGRect bounds = _mapView.bounds;
+ if (CGRectEqualToRect(bounds, CGRectZero)) {
+ // The workaround is to fix an issue that the camera location is not current when
+ // the size of the map is zero at initialization.
+ // So We only care about the size of the `_mapView`, ignore the frame changes when the size is
+ // zero.
+ return;
+ }
+ _cameraDidInitialSetup = YES;
+ [_mapView removeObserver:self forKeyPath:@"frame"];
+ [_mapView moveCamera:[GMSCameraUpdate setCamera:_mapView.camera]];
+ } else {
+ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+ }
+}
+
- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([call.method isEqualToString:@"map#show"]) {
[self showAtX:ToDouble(call.arguments[@"x"]) Y:ToDouble(call.arguments[@"y"])];
@@ -437,16 +460,6 @@
}
- (void)mapView:(GMSMapView*)mapView didChangeCameraPosition:(GMSCameraPosition*)position {
- if (!_cameraDidInitialSetup) {
- // We suspected a bug in the iOS Google Maps SDK caused the camera is not properly positioned at
- // initialization. https://github.com/flutter/flutter/issues/24806
- // This temporary workaround fix is provided while the actual fix in the Google Maps SDK is
- // still being investigated.
- // TODO(cyanglaz): Remove this temporary fix once the Maps SDK issue is resolved.
- // https://github.com/flutter/flutter/issues/27550
- _cameraDidInitialSetup = YES;
- [mapView moveCamera:[GMSCameraUpdate setCamera:_mapView.camera]];
- }
if (_trackCameraPosition) {
[_channel invokeMethod:@"camera#onMove" arguments:@{@"position" : PositionToJson(position)}];
}
@@ -511,8 +524,8 @@
static NSDictionary* PointToJson(CGPoint point) {
return @{
- @"x" : @((int)point.x),
- @"y" : @((int)point.y),
+ @"x" : @(lroundf(point.x)),
+ @"y" : @(lroundf(point.y)),
};
}
diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml
index 3d5f7b5..8c50efc 100644
--- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml
+++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml
@@ -1,7 +1,7 @@
name: google_maps_flutter
description: A Flutter plugin for integrating Google Maps in iOS and Android applications.
homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter
-version: 0.5.26+2
+version: 0.5.26+3
dependencies:
flutter: