summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Guerra <fabian.guerra@mapbox.com>2019-09-27 12:11:33 -0700
committerFabian Guerra <fabian.guerra@mapbox.com>2019-10-03 10:27:10 -0700
commit97b02c9759fd829f12a04369e8554862f065e47b (patch)
tree3802a9832e01e8f5c1e5c07c054dde542962ed9e
parent02940317aae4c8aa54e624256153c7a5a645c7b3 (diff)
downloadqtlocation-mapboxgl-97b02c9759fd829f12a04369e8554862f065e47b.tar.gz
[ios] Fix the contentInset value after adding padding to the camera.
Fixed an issue that caused a discrepancy between the contentInset in MGLMapView and the padding in the transformation state. When padding is passed through methods such as setCamera it’s persisted. This fix resets the contentInsets.
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj8
-rw-r--r--platform/ios/src/MGLMapView.mm60
-rw-r--r--platform/ios/test/MGLMapViewGestureRecognizerTests.mm280
-rw-r--r--platform/ios/test/MGLMockGestureRecognizers.h19
-rw-r--r--platform/ios/test/MGLMockGestureRecognizers.m44
5 files changed, 400 insertions, 11 deletions
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 447fb5976f..26c1979e32 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -51,6 +51,7 @@
1F7454A91ED08AB400021D39 /* MGLLightTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F7454A61ED08AB400021D39 /* MGLLightTest.mm */; };
1F8A59F72165326D004DFE75 /* sideload_sat.db in Resources */ = {isa = PBXBuildFile; fileRef = 1F8A59F62165326C004DFE75 /* sideload_sat.db */; };
1F8A59F821653275004DFE75 /* sideload_sat.db in Resources */ = {isa = PBXBuildFile; fileRef = 1F8A59F62165326C004DFE75 /* sideload_sat.db */; };
+ 1F8E8A81233A9FD9009B51ED /* MGLMapViewGestureRecognizerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F8E8A80233A9FD9009B51ED /* MGLMapViewGestureRecognizerTests.mm */; };
1F95931D1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */; };
1FC4817D2098CBC0000D09B4 /* NSPredicate+MGLPrivateAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FC4817B2098CBC0000D09B4 /* NSPredicate+MGLPrivateAdditions.h */; };
1FC4817F2098CD80000D09B4 /* NSPredicate+MGLPrivateAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FC4817B2098CBC0000D09B4 /* NSPredicate+MGLPrivateAdditions.h */; };
@@ -910,6 +911,7 @@
1F7454941ECD450D00021D39 /* MGLLight_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight_Private.h; sourceTree = "<group>"; };
1F7454A61ED08AB400021D39 /* MGLLightTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLLightTest.mm; path = ../../darwin/test/MGLLightTest.mm; sourceTree = "<group>"; };
1F8A59F62165326C004DFE75 /* sideload_sat.db */ = {isa = PBXFileReference; lastKnownFileType = file; name = sideload_sat.db; path = ../../../test/fixtures/offline_database/sideload_sat.db; sourceTree = "<group>"; };
+ 1F8E8A80233A9FD9009B51ED /* MGLMapViewGestureRecognizerTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapViewGestureRecognizerTests.mm; sourceTree = "<group>"; };
1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLNSDateAdditionsTests.mm; path = ../../darwin/test/MGLNSDateAdditionsTests.mm; sourceTree = "<group>"; };
1FC4817B2098CBC0000D09B4 /* NSPredicate+MGLPrivateAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSPredicate+MGLPrivateAdditions.h"; sourceTree = "<group>"; };
1FCAE2A020B872A400C577DD /* MGLLocationManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLLocationManager.h; sourceTree = "<group>"; };
@@ -1074,8 +1076,8 @@
5580B45A229570A10091291B /* MGLMapView+OpenGL.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "MGLMapView+OpenGL.mm"; sourceTree = "<group>"; };
558DE79E1E5615E400C7916D /* MGLFoundation_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFoundation_Private.h; sourceTree = "<group>"; };
558DE79F1E5615E400C7916D /* MGLFoundation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFoundation.mm; sourceTree = "<group>"; };
- 55CF752E213ED92000ED86C4 /* libmbgl-vendor-icu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libmbgl-vendor-icu.a; sourceTree = BUILT_PRODUCTS_DIR; };
- 55CF7530213ED92A00ED86C4 /* libmbgl-vendor-icu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libmbgl-vendor-icu.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 55CF752E213ED92000ED86C4 /* libmbgl-vendor-icu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-vendor-icu.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 55CF7530213ED92A00ED86C4 /* libmbgl-vendor-icu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-vendor-icu.a"; sourceTree = BUILT_PRODUCTS_DIR; };
55D120A71F791007004B6D81 /* libmbgl-loop-darwin.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-loop-darwin.a"; sourceTree = BUILT_PRODUCTS_DIR; };
55D120A91F79100C004B6D81 /* libmbgl-filesource.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-filesource.a"; sourceTree = BUILT_PRODUCTS_DIR; };
55D8C9941D0F133500F42F10 /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = config.xcconfig; path = ../../build/ios/config.xcconfig; sourceTree = "<group>"; };
@@ -2085,6 +2087,7 @@
96E6145522CC135200109F14 /* MGLMapViewCompassViewTests.mm */,
1F0196A923174B0700F5C819 /* MGLMapViewContentInsetTests.m */,
96ED34DD22374C0900E9FCA9 /* MGLMapViewDirectionTests.mm */,
+ 1F8E8A80233A9FD9009B51ED /* MGLMapViewGestureRecognizerTests.mm */,
16376B481FFEED010000563E /* MGLMapViewLayoutTests.m */,
96381C0122C6F3950053497D /* MGLMapViewPitchTests.m */,
9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */,
@@ -3325,6 +3328,7 @@
357579831D502AE6000B822E /* MGLRasterStyleLayerTests.mm in Sources */,
3502D6CC22AE88D5006BDFCE /* MGLAccountManagerTests.m in Sources */,
DAF25720201902BC00367EF5 /* MGLHillshadeStyleLayerTests.mm in Sources */,
+ 1F8E8A81233A9FD9009B51ED /* MGLMapViewGestureRecognizerTests.mm in Sources */,
353D23961D0B0DFE002BE09D /* MGLAnnotationViewTests.m in Sources */,
DA0CD5901CF56F6A00A5F5A5 /* MGLFeatureTests.mm in Sources */,
556660D81E1D085500E2C41B /* MGLVersionNumber.m in Sources */,
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 27ffe5fba5..486e0ad002 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -1756,7 +1756,10 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- self.mbglMap.jumpTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }));
+ self.mbglMap.jumpTo(mbgl::CameraOptions()
+ .withZoom(newZoom)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)));
// The gesture recognizer only reports the gesture’s current center
// point, so use the previous center point to anchor the transition.
@@ -1814,7 +1817,10 @@ public:
{
if (drift)
{
- self.mbglMap.easeTo(mbgl::CameraOptions().withZoom(zoom).withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }), MGLDurationFromTimeInterval(duration));
+ self.mbglMap.easeTo(mbgl::CameraOptions()
+ .withZoom(zoom)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)), MGLDurationFromTimeInterval(duration));
}
}
@@ -1879,7 +1885,8 @@ public:
{
self.mbglMap.jumpTo(mbgl::CameraOptions()
.withBearing(newDegrees)
- .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y}));
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y})
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)));
}
[self cameraIsChanging];
@@ -1920,7 +1927,8 @@ public:
{
self.mbglMap.easeTo(mbgl::CameraOptions()
.withBearing(newDegrees)
- .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }),
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)),
MGLDurationFromTimeInterval(decelerationRate));
[self notifyGestureDidEndWithDrift:YES];
@@ -2048,7 +2056,10 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
- self.mbglMap.easeTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(center), MGLDurationFromTimeInterval(MGLAnimationDuration));
+ self.mbglMap.easeTo(mbgl::CameraOptions()
+ .withZoom(newZoom)
+ .withAnchor(center)
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)), MGLDurationFromTimeInterval(MGLAnimationDuration));
__weak MGLMapView *weakSelf = self;
@@ -2086,7 +2097,10 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
- self.mbglMap.easeTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(center), MGLDurationFromTimeInterval(MGLAnimationDuration));
+ self.mbglMap.easeTo(mbgl::CameraOptions()
+ .withZoom(newZoom)
+ .withAnchor(center)
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)), MGLDurationFromTimeInterval(MGLAnimationDuration));
__weak MGLMapView *weakSelf = self;
@@ -2128,7 +2142,10 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- self.mbglMap.jumpTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }));
+ self.mbglMap.jumpTo(mbgl::CameraOptions()
+ .withZoom(newZoom)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)));
}
[self cameraIsChanging];
@@ -2195,7 +2212,8 @@ public:
{
self.mbglMap.jumpTo(mbgl::CameraOptions()
.withPitch(pitchNew)
- .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }));
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)));
}
[self cameraIsChanging];
@@ -3255,7 +3273,10 @@ public:
centerPoint = self.userLocationAnnotationViewCenter;
}
double newZoom = round(self.zoomLevel) + log2(scaleFactor);
- self.mbglMap.jumpTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }));
+ self.mbglMap.jumpTo(mbgl::CameraOptions()
+ .withZoom(newZoom)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)));
[self unrotateIfNeededForGesture];
_accessibilityValueAnnouncementIsPending = YES;
@@ -3854,6 +3875,27 @@ public:
return [self cameraForCameraOptions:cameraOptions];
}
+- (MGLMapCamera *)camera:(MGLMapCamera *)camera fittingCoordinate:(CLLocationCoordinate2D)coordinate edgePadding:(UIEdgeInsets)insets {
+ if (!_mbglMap)
+ {
+ return self.residualCamera;
+ }
+
+ mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
+ padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
+
+ MGLMapCamera *currentCamera = self.camera;
+ CGFloat pitch = camera.pitch < 0 ? currentCamera.pitch : camera.pitch;
+ CLLocationDirection direction = camera.heading < 0 ? currentCamera.heading : camera.heading;
+
+ std::vector<mbgl::LatLng> latLngs;
+ latLngs.reserve(1);
+ latLngs.push_back({coordinate.latitude, coordinate.longitude});
+
+ mbgl::CameraOptions cameraOptions = self.mbglMap.cameraForLatLngs(latLngs, padding, direction, pitch);
+ return [self cameraForCameraOptions:cameraOptions];
+}
+
- (MGLMapCamera *)camera:(MGLMapCamera *)camera fittingCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets
{
if (!_mbglMap)
diff --git a/platform/ios/test/MGLMapViewGestureRecognizerTests.mm b/platform/ios/test/MGLMapViewGestureRecognizerTests.mm
new file mode 100644
index 0000000000..58fbf2d03b
--- /dev/null
+++ b/platform/ios/test/MGLMapViewGestureRecognizerTests.mm
@@ -0,0 +1,280 @@
+#import <Mapbox/Mapbox.h>
+#import <XCTest/XCTest.h>
+
+#import "../../darwin/src/MGLGeometry_Private.h"
+#import "MGLMockGestureRecognizers.h"
+
+#include <mbgl/map/map.hpp>
+#include <mbgl/map/camera.hpp>
+
+@interface MGLMapView (MGLMapViewGestureRecognizerTests)
+
+- (mbgl::Map &)mbglMap;
+
+- (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch;
+- (void)handleRotateGesture:(UIRotationGestureRecognizer *)rotate;
+- (void)handleDoubleTapGesture:(UITapGestureRecognizer *)doubleTap;
+- (void)handleTwoFingerTapGesture:(UITapGestureRecognizer *)twoFingerTap;
+- (void)handleQuickZoomGesture:(UILongPressGestureRecognizer *)quickZoom;
+- (void)handleTwoFingerDragGesture:(UIPanGestureRecognizer *)twoFingerDrag;
+
+@end
+
+@interface MGLMapViewGestureRecognizerTests : XCTestCase <MGLMapViewDelegate>
+
+@property (nonatomic) MGLMapView *mapView;
+@property (nonatomic) UIWindow *window;
+@property (nonatomic) UIViewController *viewController;
+@property (nonatomic) XCTestExpectation *styleLoadingExpectation;
+@property (nonatomic) XCTestExpectation *twoFingerExpectation;
+@property (nonatomic) XCTestExpectation *quickZoomExpectation;
+@property (nonatomic) XCTestExpectation *doubleTapExpectation;
+@property (nonatomic) XCTestExpectation *twoFingerDragExpectation;
+@property (assign) CGRect screenBounds;
+
+@end
+
+@implementation MGLMapViewGestureRecognizerTests
+
+- (void)setUp {
+ [super setUp];
+
+ [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"];
+ NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"];
+ self.screenBounds = UIScreen.mainScreen.bounds;
+ self.mapView = [[MGLMapView alloc] initWithFrame:self.screenBounds styleURL:styleURL];
+ self.mapView.zoomLevel = 16;
+ self.mapView.delegate = self;
+
+ self.viewController = [[UIViewController alloc] init];
+ self.viewController.view = [[UIView alloc] initWithFrame:self.screenBounds];
+ [self.viewController.view addSubview:self.mapView];
+ self.window = [[UIWindow alloc] initWithFrame:self.screenBounds];
+ [self.window addSubview:self.viewController.view];
+ [self.window makeKeyAndVisible];
+
+ if (!self.mapView.style) {
+ _styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."];
+ [self waitForExpectationsWithTimeout:10 handler:nil];
+ }
+}
+
+- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style {
+ XCTAssertNotNil(mapView.style);
+ XCTAssertEqual(mapView.style, style);
+
+ [_styleLoadingExpectation fulfill];
+}
+
+- (void)testHandlePinchGestureContentInset {
+ UIEdgeInsets contentInset = UIEdgeInsetsZero;
+ self.mapView.contentInset = contentInset;
+ mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.mapView.contentInset);
+ auto cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"MGLMapView's contentInset property should match camera's padding.");
+ XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset));
+
+ contentInset = UIEdgeInsetsMake(20, 20, 20, 20);
+ [self.mapView setCamera:self.mapView.camera withDuration:0.1 animationTimingFunction:nil edgePadding:contentInset completionHandler:nil];
+ XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset));
+
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertNotEqual(padding, cameraPadding);
+
+ UIPinchGestureRecognizerMock *pinchGesture = [[UIPinchGestureRecognizerMock alloc] initWithTarget:nil action:nil];
+ pinchGesture.state = UIGestureRecognizerStateBegan;
+ pinchGesture.scale = 1.0;
+ [self.mapView handlePinchGesture:pinchGesture];
+ XCTAssertNotEqual(padding, cameraPadding);
+
+ pinchGesture.state = UIGestureRecognizerStateChanged;
+ [self.mapView handlePinchGesture:pinchGesture];
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match.");
+
+ pinchGesture.state = UIGestureRecognizerStateEnded;
+ [self.mapView handlePinchGesture:pinchGesture];
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match.");
+
+}
+
+- (void)testHandleRotateGestureContentInset {
+ UIEdgeInsets contentInset = UIEdgeInsetsZero;
+ self.mapView.contentInset = contentInset;
+ mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.mapView.contentInset);
+ auto cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"MGLMapView's contentInset property should match camera's padding.");
+ XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset));
+
+ contentInset = UIEdgeInsetsMake(20, 20, 20, 20);
+ [self.mapView setCamera:self.mapView.camera withDuration:0.1 animationTimingFunction:nil edgePadding:contentInset completionHandler:nil];
+ XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset));
+
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertNotEqual(padding, cameraPadding);
+
+ UIRotationGestureRecognizerMock *rotateGesture = [[UIRotationGestureRecognizerMock alloc] initWithTarget:nil action:nil];
+ rotateGesture.state = UIGestureRecognizerStateBegan;
+ rotateGesture.rotation = 1;
+ [self.mapView handleRotateGesture:rotateGesture];
+ XCTAssertNotEqual(padding, cameraPadding);
+
+ rotateGesture.state = UIGestureRecognizerStateChanged;
+ [self.mapView handleRotateGesture:rotateGesture];
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match.");
+
+ rotateGesture.state = UIGestureRecognizerStateEnded;
+ [self.mapView handleRotateGesture:rotateGesture];
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match.");
+
+}
+
+- (void)testHandleDoubleTapGestureContentInset {
+ UIEdgeInsets contentInset = UIEdgeInsetsMake(1, 1, 1, 1);
+ self.mapView.contentInset = contentInset;
+ mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.mapView.contentInset);
+ auto cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"MGLMapView's contentInset property should match camera's padding.");
+ XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset));
+
+ contentInset = UIEdgeInsetsMake(20, 20, 20, 20);
+ [self.mapView setCamera:self.mapView.camera withDuration:0.1 animationTimingFunction:nil edgePadding:contentInset completionHandler:nil];
+ XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset));
+
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertNotEqual(padding, cameraPadding);
+
+ UITapGestureRecognizerMock *doubleTapGesture = [[UITapGestureRecognizerMock alloc] initWithTarget:nil action:nil];
+ doubleTapGesture.mockTappedView = self.mapView;
+ doubleTapGesture.mockTappedPoint = CGPointMake(1.0, 1.0);
+
+ [self.mapView handleDoubleTapGesture:doubleTapGesture];
+ _doubleTapExpectation = [self expectationWithDescription:@"Double tap gesture animation."];
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ [self->_doubleTapExpectation fulfill];
+ });
+ [self waitForExpectationsWithTimeout:10 handler:nil];
+
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match.");
+
+}
+
+- (void)testHandleTwoFingerTapGesture {
+ UIEdgeInsets contentInset = UIEdgeInsetsZero;
+ self.mapView.contentInset = contentInset;
+ mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.mapView.contentInset);
+ auto cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"MGLMapView's contentInset property should match camera's padding.");
+ XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset));
+
+ contentInset = UIEdgeInsetsMake(20, 20, 20, 20);
+ [self.mapView setCamera:self.mapView.camera withDuration:0.1 animationTimingFunction:nil edgePadding:contentInset completionHandler:nil];
+ XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset));
+
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertNotEqual(padding, cameraPadding);
+
+ UITapGestureRecognizerMock *twoFingerTap = [[UITapGestureRecognizerMock alloc] initWithTarget:nil action:nil];
+ twoFingerTap.mockTappedView = self.mapView;
+ twoFingerTap.mockTappedPoint = CGPointMake(1.0, 1.0);
+
+ [self.mapView handleTwoFingerTapGesture:twoFingerTap];
+ _twoFingerExpectation = [self expectationWithDescription:@"Two Finger tap gesture animation."];
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ [self->_twoFingerExpectation fulfill];
+ });
+ [self waitForExpectationsWithTimeout:10 handler:nil];
+
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match.");
+}
+
+- (void)testHandleQuickZoomGesture {
+ UIEdgeInsets contentInset = UIEdgeInsetsZero;
+ self.mapView.contentInset = contentInset;
+ mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.mapView.contentInset);
+ auto cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"MGLMapView's contentInset property should match camera's padding.");
+ XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset));
+
+ contentInset = UIEdgeInsetsMake(20, 20, 20, 20);
+ [self.mapView setCamera:self.mapView.camera withDuration:0.1 animationTimingFunction:nil edgePadding:contentInset completionHandler:nil];
+ XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset));
+
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertNotEqual(padding, cameraPadding);
+
+ UILongPressGestureRecognizerMock *quickZoom = [[UILongPressGestureRecognizerMock alloc] initWithTarget:nil action:nil];
+ quickZoom.state = UIGestureRecognizerStateBegan;
+ [self.mapView handleQuickZoomGesture:quickZoom];
+ XCTAssertNotEqual(padding, cameraPadding);
+
+ quickZoom.state = UIGestureRecognizerStateChanged;
+ quickZoom.mockTappedPoint = CGPointMake(self.mapView.frame.size.width / 2, self.mapView.frame.size.height / 2);
+ [self.mapView handleQuickZoomGesture:quickZoom];
+ _quickZoomExpectation = [self expectationWithDescription:@"Quick zoom gesture animation."];
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ [self->_quickZoomExpectation fulfill];
+ });
+ [self waitForExpectationsWithTimeout:10 handler:nil];
+
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match.");
+
+ quickZoom.state = UIGestureRecognizerStateEnded;
+ [self.mapView handleQuickZoomGesture:quickZoom];
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match.");
+}
+
+- (void)testHandleTwoFingerDragGesture {
+ UIEdgeInsets contentInset = UIEdgeInsetsZero;
+ self.mapView.contentInset = contentInset;
+ mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.mapView.contentInset);
+ auto cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"MGLMapView's contentInset property should match camera's padding.");
+ XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset));
+
+ contentInset = UIEdgeInsetsMake(20, 20, 20, 20);
+ [self.mapView setCamera:self.mapView.camera withDuration:0.1 animationTimingFunction:nil edgePadding:contentInset completionHandler:nil];
+ XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset));
+
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertNotEqual(padding, cameraPadding);
+
+ UIPanGestureRecognizerMock *twoFingerDrag = [[UIPanGestureRecognizerMock alloc] initWithTarget:nil action:nil];
+ twoFingerDrag.state = UIGestureRecognizerStateBegan;
+ twoFingerDrag.firstFingerPoint = CGPointMake(self.mapView.frame.size.width / 3, self.mapView.frame.size.height/2);
+ twoFingerDrag.secondFingerPoint = CGPointMake((self.mapView.frame.size.width / 2), self.mapView.frame.size.height/2);
+ twoFingerDrag.numberOfTouches = 2;
+ [self.mapView handleTwoFingerDragGesture:twoFingerDrag];
+ XCTAssertNotEqual(padding, cameraPadding);
+
+ twoFingerDrag.state = UIGestureRecognizerStateChanged;
+ twoFingerDrag.firstFingerPoint = CGPointMake(self.mapView.frame.size.width / 3, (self.mapView.frame.size.height/2)-10);
+ twoFingerDrag.secondFingerPoint = CGPointMake((self.mapView.frame.size.width / 2), (self.mapView.frame.size.height/2)-10);
+ [self.mapView handleTwoFingerDragGesture:twoFingerDrag];
+ _twoFingerDragExpectation = [self expectationWithDescription:@"Quick zoom gesture animation."];
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ [self->_twoFingerDragExpectation fulfill];
+ });
+ [self waitForExpectationsWithTimeout:10 handler:nil];
+
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match.");
+
+ twoFingerDrag.state = UIGestureRecognizerStateEnded;
+ [self.mapView handleTwoFingerDragGesture:twoFingerDrag];
+ cameraPadding = self.mapView.mbglMap.getCameraOptions().padding;
+ XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match.");
+}
+
+@end
diff --git a/platform/ios/test/MGLMockGestureRecognizers.h b/platform/ios/test/MGLMockGestureRecognizers.h
index aa5fbec494..29889e39f4 100644
--- a/platform/ios/test/MGLMockGestureRecognizers.h
+++ b/platform/ios/test/MGLMockGestureRecognizers.h
@@ -4,7 +4,26 @@
@interface UIPinchGestureRecognizerMock : UIPinchGestureRecognizer
@property (nonatomic, readwrite) CGFloat velocity;
@property (nonatomic) CGPoint locationInViewOverride;
+@property(nonatomic, readwrite) UIGestureRecognizerState state;
@end
@interface UIRotationGestureRecognizerMock : UIRotationGestureRecognizer
+@property(nonatomic, readwrite) UIGestureRecognizerState state;
+@end
+
+@interface UITapGestureRecognizerMock : UITapGestureRecognizer
+@property (strong, nonatomic) UIView *mockTappedView;
+@property (assign) CGPoint mockTappedPoint;
+@end
+
+@interface UILongPressGestureRecognizerMock : UILongPressGestureRecognizer
+@property(nonatomic, readwrite) UIGestureRecognizerState state;
+@property (assign) CGPoint mockTappedPoint;
+@end
+
+@interface UIPanGestureRecognizerMock : UIPanGestureRecognizer
+@property(nonatomic, readwrite) UIGestureRecognizerState state;
+@property (assign) CGPoint firstFingerPoint;
+@property (assign) CGPoint secondFingerPoint;
+@property(nonatomic, readwrite) NSUInteger numberOfTouches;
@end
diff --git a/platform/ios/test/MGLMockGestureRecognizers.m b/platform/ios/test/MGLMockGestureRecognizers.m
index 89df6750a9..c818805174 100644
--- a/platform/ios/test/MGLMockGestureRecognizers.m
+++ b/platform/ios/test/MGLMockGestureRecognizers.m
@@ -1,11 +1,55 @@
#import "MGLMockGestureRecognizers.h"
+#import "objc/runtime.h"
@implementation UIPinchGestureRecognizerMock
@synthesize velocity;
+@synthesize state;
- (CGPoint)locationInView:(nullable UIView *)view { return self.locationInViewOverride; }
@end
@implementation UIRotationGestureRecognizerMock
- (CGPoint)locationInView:(nullable UIView*)view { return view.center; }
+@synthesize state;
+@end
+
+@implementation UITapGestureRecognizerMock
+
++ (void)load {
+ method_exchangeImplementations(class_getInstanceMethod(self, @selector(state)),
+ class_getInstanceMethod(self, @selector(mockState)));
+}
+
+- (UIGestureRecognizerState)mockState {
+ return UIGestureRecognizerStateRecognized;
+}
+
+- (UIView *)view {
+ return self.mockTappedView;
+}
+
+- (CGPoint)locationInView:(UIView *)view {
+ return self.mockTappedPoint;
+}
+
+@end
+
+@implementation UILongPressGestureRecognizerMock
+@synthesize state;
+
+- (CGPoint)locationInView:(UIView *)view {
+ return self.mockTappedPoint;
+}
+@end
+
+@implementation UIPanGestureRecognizerMock
+@synthesize state;
+@synthesize numberOfTouches;
+
+- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(UIView *)view {
+ if (touchIndex) {
+ return self.secondFingerPoint;
+ }
+ return self.firstFingerPoint;
+}
@end