Skip to content
This repository has been archived by the owner on Jun 21, 2023. It is now read-only.

Commit

Permalink
[ios] Add delegate method to specify the user location annotation’s p…
Browse files Browse the repository at this point in the history
…osition

Update method name

More API drafting

Add deprecation flag

Add Swift delegate integration test

Update method name and documentation

Update deprecation notices

Update method name

Offset anchor point relative to contentFrame

Update docs

Only run through switch statement if delegate is unimplemented

Account for content inset + refactor logic

Adjust edgePaddingForFollowing

Fix Swift delegate integration test

Set up integration test

Set up test location manager

.

Remove unused file reference from test

Return CGPoint value from delegate method within integration test setup

Test anchor points

Make updateUserLocationAnnotationView public

Refactor test

Update test location manager

Changelog entry

Doc fixes
  • Loading branch information
captainbarbosa committed Oct 2, 2018
1 parent 41dd886 commit 7b24339
Show file tree
Hide file tree
Showing 12 changed files with 147 additions and 8 deletions.
6 changes: 6 additions & 0 deletions platform/ios/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Fixed a crash when a style layer `*-pattern` property evaluates to nil for a particular feature. ([#12896](https://github.com/mapbox/mapbox-gl-native/pull/12896))
* Fixed an issue with view annotations (including the user location annotation) and the GL map lagging relative to each other. ([#12895](https://github.com/mapbox/mapbox-gl-native/pull/12895))

### User location
* Added `-[MGLMapViewDelegate mapViewUserLocationAnchorPoint:]` to customize the position of the user location annotation.. ([#12907](https://github.com/mapbox/mapbox-gl-native/pull/12907))
* Marked `-[MGLMapView setUserLocationVerticalAlignment:]` as deprecated. Use `-[MGLMapViewDelegate mapViewUserLocationAnchorPoint:]` instead. ([#12907](https://github.com/mapbox/mapbox-gl-native/pull/12907))
* Added the `-[MGLMapView updateUserLocationAnnotationView]` and `-[MGLMapView updateUserLocationAnnotationView:animated:]` methods to update the position of the user location annotation between location updates. ([#12907](https://github.com/mapbox/mapbox-gl-native/pull/12907))
* Fixed an issue where the user location annotation was positioned incorrectly when the map view had a left or right content inset. ([#12907](https://github.com/mapbox/mapbox-gl-native/pull/12907)) inset

### Offline maps

* Added `-[MGLOfflineStorage addContentsOfFile:withCompletionHandler:]` and `-[MGLOfflineStorage addContentsOfURL:withCompletionHandler:]` methods to add pregenerated offline packs to offline storage. ([#12791](https://github.com/mapbox/mapbox-gl-native/pull/12791))
Expand Down
2 changes: 2 additions & 0 deletions platform/ios/Integration Test Harness/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Used to run user location tests</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "MGLMapViewIntegrationTest.h"
#import "MGLTestUtility.h"
#import "MGLMapAccessibilityElement.h"
#import "MGLTestLocationManager.h"

@interface MGLMapView (Tests)
- (MGLAnnotationTag)annotationTagAtPoint:(CGPoint)point persistingResults:(BOOL)persist;
Expand Down Expand Up @@ -91,6 +92,31 @@ - (void)internalTestSelectingAnnotationWithCenterOffsetWithOffset:(CGVector)offs
}
}

- (void)testUserLocationWithOffsetAnchorPoint {
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(37.787357, -122.39899)];
MGLTestLocationManager *locationManager = [[MGLTestLocationManager alloc] init];
self.mapView.locationManager = locationManager;

[self.mapView setUserTrackingMode:MGLUserTrackingModeFollow animated:NO];
CGRect originalFrame = [self.mapView viewForAnnotation:self.mapView.userLocation].frame;

// Temporarily disable location tracking so we can save the value of
// the originalFrame in memory
[self.mapView setUserTrackingMode:MGLUserTrackingModeNone animated:NO];

CGPoint offset = CGPointMake(20, 20);

self.mapViewUserLocationAnchorPoint = ^CGPoint (MGLMapView *mapView) {
return offset;;
};

[self.mapView setUserTrackingMode:MGLUserTrackingModeFollow animated:NO];
CGRect offsetFrame = [self.mapView viewForAnnotation:self.mapView.userLocation].frame;

XCTAssertEqual(originalFrame.origin.x + offset.x, offsetFrame.origin.x);
XCTAssertEqual(originalFrame.origin.y + offset.y, offsetFrame.origin.y);
}

- (void)waitForCollisionDetectionToRun {
XCTAssertNil(self.renderFinishedExpectation, @"Incorrect test setup");

Expand Down
1 change: 1 addition & 0 deletions platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
@property (nonatomic) void (^regionWillChange)(MGLMapView *mapView, BOOL animated);
@property (nonatomic) void (^regionIsChanging)(MGLMapView *mapView);
@property (nonatomic) void (^regionDidChange)(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated);
@property (nonatomic) CGPoint (^mapViewUserLocationAnchorPoint)(MGLMapView *mapView);

// Utility methods
- (NSString*)validAccessToken;
Expand Down
7 changes: 7 additions & 0 deletions platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ - (void)mapView:(MGLMapView *)mapView regionDidChangeWithReason:(MGLCameraChange
}
}

- (CGPoint)mapViewUserLocationAnchorPoint:(MGLMapView *)mapView {
if (self.mapViewUserLocationAnchorPoint) {
return self.mapViewUserLocationAnchorPoint(mapView);
}
return CGPointZero;
}

#pragma mark - Utilities

- (void)waitForMapViewToFinishLoadingStyleWithTimeout:(NSTimeInterval)timeout {
Expand Down
10 changes: 10 additions & 0 deletions platform/ios/Integration Tests/MGLTestLocationManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#import <XCTest/XCTest.h>
#import <Mapbox/Mapbox.h>
#import "MGLTestUtility.h"

@interface MGLTestLocationManager : NSObject<MGLLocationManager>
@end

@interface MGLTestLocationManager()

@end
44 changes: 44 additions & 0 deletions platform/ios/Integration Tests/MGLTestLocationManager.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#import "MGLTestLocationManager.h"

// Used to supply integration tests with a simulated location manager.
// Methods that are empty are not used within integration tests and are
// therefore unimplemented.

@implementation MGLTestLocationManager

@synthesize delegate;

- (CLAuthorizationStatus)authorizationStatus { return kCLAuthorizationStatusAuthorizedAlways; }

- (void)setHeadingOrientation:(CLDeviceOrientation)headingOrientation { }

- (CLDeviceOrientation)headingOrientation { return 90; }

- (void)requestAlwaysAuthorization { }

- (void)requestWhenInUseAuthorization { }

- (void)startUpdatingHeading { }

// Simulate one location update
- (void)startUpdatingLocation
{
if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateLocations:)]) {
CLLocation *location = [[CLLocation alloc] initWithLatitude:37.787357 longitude:-122.39899];
[self.delegate locationManager:self didUpdateLocations:@[location]];
}
}

- (void)stopUpdatingHeading { }

- (void)stopUpdatingLocation { }

- (void)dismissHeadingCalibrationDisplay { }

- (void)dealloc { self.delegate = nil; }

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading { }

- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager { return NO; }

@end
7 changes: 7 additions & 0 deletions platform/ios/ios.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
071BBB071EE77631001FB02A /* MGLImageSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */; };
076171C32139C70900668A35 /* MGLMapViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 076171C22139C70900668A35 /* MGLMapViewTests.m */; };
076171C72141A91700668A35 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 076171C62141A91700668A35 /* Settings.bundle */; };
077061D6215D97EF000FEF62 /* simple_route.json in Resources */ = {isa = PBXBuildFile; fileRef = 1F26B6C220E1A351007BCC21 /* simple_route.json */; };
077061DA215DA00E000FEF62 /* MGLTestLocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 077061D9215DA00E000FEF62 /* MGLTestLocationManager.m */; };
0778DD431F67556700A73B34 /* MGLComputedShapeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 0778DD401F67555F00A73B34 /* MGLComputedShapeSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
0778DD441F67556C00A73B34 /* MGLComputedShapeSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0778DD411F67555F00A73B34 /* MGLComputedShapeSource.mm */; };
07D8C6FB1F67560100381808 /* MGLComputedShapeSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0778DD411F67555F00A73B34 /* MGLComputedShapeSource.mm */; };
Expand Down Expand Up @@ -747,6 +749,8 @@
071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLImageSourceTests.m; path = ../../darwin/test/MGLImageSourceTests.m; sourceTree = "<group>"; };
076171C22139C70900668A35 /* MGLMapViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLMapViewTests.m; path = ../../darwin/test/MGLMapViewTests.m; sourceTree = "<group>"; };
076171C62141A91700668A35 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = Settings.bundle; path = app/Settings.bundle; sourceTree = SOURCE_ROOT; };
077061D9215DA00E000FEF62 /* MGLTestLocationManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLTestLocationManager.m; sourceTree = "<group>"; };
077061DB215DA11F000FEF62 /* MGLTestLocationManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLTestLocationManager.h; sourceTree = "<group>"; };
0778DD401F67555F00A73B34 /* MGLComputedShapeSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLComputedShapeSource.h; sourceTree = "<group>"; };
0778DD411F67555F00A73B34 /* MGLComputedShapeSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLComputedShapeSource.mm; sourceTree = "<group>"; };
07D8C6FD1F67562800381808 /* MGLComputedShapeSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLComputedShapeSourceTests.m; path = ../../darwin/test/MGLComputedShapeSourceTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1376,6 +1380,8 @@
CA0C27932076CA19001CE5B7 /* MGLMapViewIntegrationTest.m */,
CA0C27952076CA50001CE5B7 /* MGLMapViewIntegrationTest.h */,
CA4EB8C620863487006AB465 /* MGLStyleLayerIntegrationTests.m */,
077061DB215DA11F000FEF62 /* MGLTestLocationManager.h */,
077061D9215DA00E000FEF62 /* MGLTestLocationManager.m */,
);
path = "Integration Tests";
sourceTree = "<group>";
Expand Down Expand Up @@ -2825,6 +2831,7 @@
CA0C27942076CA19001CE5B7 /* MGLMapViewIntegrationTest.m in Sources */,
CAE7AD5520F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift in Sources */,
CA0C27922076C804001CE5B7 /* MGLShapeSourceTests.m in Sources */,
077061DA215DA00E000FEF62 /* MGLTestLocationManager.m in Sources */,
CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m in Sources */,
CA1B4A512099FB2200EDD491 /* MGLMapSnapshotterTest.m in Sources */,
);
Expand Down
17 changes: 15 additions & 2 deletions platform/ios/src/MGLMapView.h
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ MGL_EXPORT IB_DESIGNABLE
transition. If you don’t want to animate the change, use the
`-setUserLocationVerticalAlignment:animated:` method instead.
*/
@property (nonatomic, assign) MGLAnnotationVerticalAlignment userLocationVerticalAlignment;
@property (nonatomic, assign) MGLAnnotationVerticalAlignment userLocationVerticalAlignment __attribute__((deprecated("Use -[MGLMapViewDelegate mapViewUserLocationAnchorPoint:] instead.")));

/**
Sets the vertical alignment of the user location annotation within the
Expand All @@ -427,7 +427,20 @@ MGL_EXPORT IB_DESIGNABLE
position within the map view. If `NO`, the user location annotation
instantaneously moves to its new position.
*/
- (void)setUserLocationVerticalAlignment:(MGLAnnotationVerticalAlignment)alignment animated:(BOOL)animated;
- (void)setUserLocationVerticalAlignment:(MGLAnnotationVerticalAlignment)alignment animated:(BOOL)animated __attribute__((deprecated("Use -[MGLMapViewDelegate mapViewUserLocationAnchorPoint:] instead.")));

/**
Updates the position of the user location annotation view by retreiving the user's last
known location.
*/
- (void)updateUserLocationAnnotationView;

/**
Updates the position of the user location annotation view by retreiving the user's last
known location with a specified duration.
@param duration The duration to animate the change in seconds.
*/
- (void)updateUserLocationAnnotationViewAnimatedWithDuration:(NSTimeInterval)duration;

/**
A Boolean value indicating whether the user location annotation may display a
Expand Down
18 changes: 12 additions & 6 deletions platform/ios/src/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5280,9 +5280,9 @@ - (UIEdgeInsets)edgePaddingForFollowing
correctPoint.x - CGRectGetMidX(bounds),
correctPoint.y - CGRectGetMidY(bounds));
return UIEdgeInsetsMake(CGRectGetMinY(boundsAroundCorrectPoint) - CGRectGetMinY(bounds),
self.contentInset.left,
CGRectGetMaxX(boundsAroundCorrectPoint) - CGRectGetMaxX(bounds),
CGRectGetMaxY(bounds) - CGRectGetMaxY(boundsAroundCorrectPoint),
self.contentInset.right);
CGRectGetMaxX(bounds) - CGRectGetMaxX(boundsAroundCorrectPoint));
}

/// Returns the edge padding to apply during bifocal course tracking.
Expand Down Expand Up @@ -5998,15 +5998,21 @@ - (void)updateUserLocationAnnotationViewAnimatedWithDuration:(NSTimeInterval)dur
/// the overall map view (but respecting the content inset).
- (CGPoint)userLocationAnnotationViewCenter
{
if ([self.delegate respondsToSelector:@selector(mapViewUserLocationAnchorPoint:)])
{
CGPoint anchorPoint = [self.delegate mapViewUserLocationAnchorPoint:self];
return CGPointMake(anchorPoint.x + self.contentInset.left, anchorPoint.y + self.contentInset.top);
}

CGRect contentFrame = UIEdgeInsetsInsetRect(self.contentFrame, self.edgePaddingForFollowingWithCourse);

if (CGRectIsEmpty(contentFrame))
{
contentFrame = self.contentFrame;
}

CGPoint center = CGPointMake(CGRectGetMidX(contentFrame), CGRectGetMidY(contentFrame));

// When tracking course, it’s more important to see the road ahead, so
// weight the user dot down towards the bottom.

switch (self.userLocationVerticalAlignment) {
case MGLAnnotationVerticalAlignmentCenter:
break;
Expand All @@ -6017,7 +6023,7 @@ - (CGPoint)userLocationAnnotationViewCenter
center.y = CGRectGetMaxY(contentFrame);
break;
}

return center;
}

Expand Down
15 changes: 15 additions & 0 deletions platform/ios/src/MGLMapViewDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,21 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)mapView:(MGLMapView *)mapView didChangeUserTrackingMode:(MGLUserTrackingMode)mode animated:(BOOL)animated;

/**
Returns a screen coordinate at which to position the user location annotation.
This coordinate is relative to the map view’s origin after applying the map view’s
content insets.
When unimplemented, the user location annotation is aligned within the center of
the map view with respect to the content insets.
This method will override any values set by `MGLMapView.userLocationVerticalAlignment`
or `-[MGLMapView setUserLocationVerticalAlignment:]`.
@param mapView The map view that is tracking the user's location.
*/
- (CGPoint)mapViewUserLocationAnchorPoint:(MGLMapView *)mapView;

#pragma mark Managing the Appearance of Annotations

/**
Expand Down
2 changes: 2 additions & 0 deletions platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,6 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
func mapView(_ mapView: MGLMapView, shouldChangeFrom oldCamera: MGLMapCamera, to newCamera: MGLMapCamera) -> Bool { return false }

func mapView(_ mapView: MGLMapView, shouldChangeFrom oldCamera: MGLMapCamera, to newCamera: MGLMapCamera, reason: MGLCameraChangeReason) -> Bool { return false }

func mapViewUserLocationAnchorPoint(_ mapView: MGLMapView) -> CGPoint { return CGPoint(x: 100, y: 100) }
}

0 comments on commit 7b24339

Please sign in to comment.