summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--include/mbgl/ios/MGLMapView.h25
-rw-r--r--include/mbgl/map/camera.hpp4
-rw-r--r--platform/ios/MGLMapView.mm52
-rw-r--r--src/mbgl/map/transform.cpp9
5 files changed, 85 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 06d8787213..ace53f9e7b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,7 @@ Known issues:
## iOS master
+- `MGLMapView` methods that alter the viewport now accept optional completion handlers. ([#3090](https://github.com/mapbox/mapbox-gl-native/pull/3090))
- Fixed an issue preventing the compass from responding to taps after the compass is moved programmatically. ([#3117](https://github.com/mapbox/mapbox-gl-native/pull/3117))
## iOS 3.0.0
diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h
index 83ef395cf9..edc3ca53f3 100644
--- a/include/mbgl/ios/MGLMapView.h
+++ b/include/mbgl/ios/MGLMapView.h
@@ -134,6 +134,14 @@ IB_DESIGNABLE
* @param animated Specify `YES` if you want the map view to animate scrolling, zooming, and rotating to the new location or `NO` if you want the map to display the new location immediately. */
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated;
+/** Changes the center coordinate, zoom level, and direction of the map, calling a completion handler at the end of an optional animation.
+* @param centerCoordinate The new center coordinate for the map.
+* @param zoomLevel The new zoom level for the map.
+* @param direction The new direction for the map, measured in degrees relative to true north.
+* @param animated Specify `YES` if you want the map view to animate scrolling, zooming, and rotating to the new location or `NO` if you want the map to display the new location immediately.
+* @param completion The block executed after the animation finishes. */
+- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion;
+
/** The coordinate bounds visible in the receiver’s viewport.
*
* Changing the value of this property updates the receiver immediately. If you want to animate the change, call `setVisibleCoordinateBounds:animated:` instead. */
@@ -157,6 +165,16 @@ IB_DESIGNABLE
* @param animated Specify `YES` to animate the change by smoothly scrolling and zooming or `NO` to immediately display the given bounds. */
- (void)setVisibleCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated;
+/** Changes the receiver’s viewport to fit all of the given coordinates and optionally some additional padding on each side.
+* @param coordinates The coordinates that the viewport will show.
+* @param count The number of coordinates. This number must not be greater than the number of elements in `coordinates`.
+* @param insets The minimum padding (in screen points) that will be visible around the given coordinate bounds.
+* @param direction The direction to rotate the map to, measured in degrees relative to true north.
+* @param duration The duration to animate the change in seconds.
+* @param function The timing function to animate the change.
+* @param completion The block executed after the animation finishes. */
+- (void)setVisibleCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets direction:(CLLocationDirection)direction duration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion;
+
/** Sets the visible region so that the map displays the specified annotations.
*
* Calling this method updates the value in the visibleCoordinateBounds property and potentially other properties to reflect the new map region.
@@ -193,6 +211,13 @@ IB_DESIGNABLE
* @param function A timing function used for the animation. Set this parameter to `nil` for a transition that matches most system animations. If the duration is `0`, this parameter is ignored. */
- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function;
+/** Moves the viewpoint to a different location with respect to the map with an optional transition duration and timing function.
+* @param camera The new viewpoint.
+* @param duration The amount of time, measured in seconds, that the transition animation should take. Specify `0` to jump to the new viewpoint instantaneously.
+* @param function A timing function used for the animation. Set this parameter to `nil` for a transition that matches most system animations. If the duration is `0`, this parameter is ignored.
+* @param completion The block to execute after the animation finishes. */
+- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion;
+
#pragma mark - Converting Map Coordinates
/** @name Converting Map Coordinates */
diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp
index a16c1d4dc2..d787a39e11 100644
--- a/include/mbgl/map/camera.hpp
+++ b/include/mbgl/map/camera.hpp
@@ -7,6 +7,8 @@
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/unitbezier.hpp>
+#include <functional>
+
namespace mbgl {
struct CameraOptions {
@@ -16,6 +18,8 @@ struct CameraOptions {
mapbox::util::optional<double> pitch;
mapbox::util::optional<Duration> duration;
mapbox::util::optional<mbgl::util::UnitBezier> easing;
+ std::function<void(double)> transitionFrameFn;
+ std::function<void()> transitionFinishFn;
};
}
diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm
index 452b307575..c923adb160 100644
--- a/platform/ios/MGLMapView.mm
+++ b/platform/ios/MGLMapView.mm
@@ -1565,14 +1565,18 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
[self setCenterCoordinate:centerCoordinate zoomLevel:zoomLevel direction:self.direction animated:animated];
}
-- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated
+- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated {
+ [self setCenterCoordinate:centerCoordinate zoomLevel:zoomLevel direction:direction animated:animated completionHandler:NULL];
+}
+
+- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion
{
self.userTrackingMode = MGLUserTrackingModeNone;
- [self _setCenterCoordinate:centerCoordinate zoomLevel:zoomLevel direction:direction animated:animated];
+ [self _setCenterCoordinate:centerCoordinate zoomLevel:zoomLevel direction:direction animated:animated completionHandler:completion];
}
-- (void)_setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated
+- (void)_setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion
{
_mbglMap->cancelTransitions();
@@ -1589,6 +1593,17 @@ std::chrono::steady_clock::duration durationInSeconds(float duration)
options.duration = durationInSeconds(duration);
options.easing = MGLUnitBezierForMediaTimingFunction(nil);
}
+ if (completion)
+ {
+ options.transitionFinishFn = [completion]() {
+ // Must run asynchronously after the transition is completely over.
+ // Otherwise, a call to -setCenterCoordinate: within the completion
+ // handler would reenter the completion handler’s caller.
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ completion();
+ });
+ };
+ }
_mbglMap->easeTo(options);
[self unrotateIfNeededAnimated:animated];
@@ -1679,7 +1694,11 @@ mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBounds coord
[self setVisibleCoordinates:coordinates count:count edgePadding:insets direction:direction duration:animated ? MGLAnimationDuration : 0 animationTimingFunction:nil];
}
-- (void)setVisibleCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets direction:(CLLocationDirection)direction duration:(NSTimeInterval)duration animationTimingFunction:(CAMediaTimingFunction *)function
+- (void)setVisibleCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets direction:(CLLocationDirection)direction duration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function {
+ [self setVisibleCoordinates:coordinates count:count edgePadding:insets direction:direction duration:duration animationTimingFunction:function completionHandler:NULL];
+}
+
+- (void)setVisibleCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets direction:(CLLocationDirection)direction duration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion
{
_mbglMap->cancelTransitions();
@@ -1702,6 +1721,14 @@ mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBounds coord
options.duration = durationInSeconds(duration);
options.easing = MGLUnitBezierForMediaTimingFunction(function);
}
+ if (completion)
+ {
+ options.transitionFinishFn = [completion]() {
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ completion();
+ });
+ };
+ }
_mbglMap->easeTo(options);
[self didChangeValueForKey:@"visibleCoordinateBounds"];
@@ -1815,7 +1842,12 @@ mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBounds coord
[self setCamera:camera withDuration:animated ? MGLAnimationDuration : 0 animationTimingFunction:nil];
}
-- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(CAMediaTimingFunction *)function
+- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function
+{
+ [self setCamera:camera withDuration:duration animationTimingFunction:function completionHandler:NULL];
+}
+
+- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion
{
_mbglMap->cancelTransitions();
@@ -1880,6 +1912,14 @@ mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBounds coord
options.duration = durationInSeconds(duration);
options.easing = MGLUnitBezierForMediaTimingFunction(function);
}
+ if (completion)
+ {
+ options.transitionFinishFn = [completion]() {
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ completion();
+ });
+ };
+ }
_mbglMap->easeTo(options);
}
@@ -2675,7 +2715,7 @@ CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng)
{
// at sufficient detail, just re-center the map; don't zoom
//
- [self _setCenterCoordinate:self.userLocation.location.coordinate zoomLevel:self.zoomLevel direction:course animated:YES];
+ [self _setCenterCoordinate:self.userLocation.location.coordinate zoomLevel:self.zoomLevel direction:course animated:YES completionHandler:NULL];
}
else
{
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index 55a492c493..7f0363c709 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -262,6 +262,9 @@ void Transform::_easeTo(const CameraOptions& options, double new_scale, double n
state.angle = angle;
state.pitch = pitch;
+ if (options.transitionFinishFn) {
+ options.transitionFinishFn();
+ }
view.notifyMapChange(MapChangeRegionDidChange);
} else {
view.notifyMapChange(MapChangeRegionWillChangeAnimated);
@@ -291,6 +294,9 @@ void Transform::_easeTo(const CameraOptions& options, double new_scale, double n
state.pitch = util::interpolate(startP, pitch, t);
// At t = 1.0, a DidChangeAnimated notification should be sent from finish().
if (t < 1.0) {
+ if (options.transitionFrameFn) {
+ options.transitionFrameFn(t);
+ }
view.notifyMapChange(MapChangeRegionIsChanging);
}
return update;
@@ -299,6 +305,9 @@ void Transform::_easeTo(const CameraOptions& options, double new_scale, double n
state.panning = false;
state.scaling = false;
state.rotating = false;
+ if (options.transitionFinishFn) {
+ options.transitionFinishFn();
+ }
view.notifyMapChange(MapChangeRegionDidChangeAnimated);
}, *easeOptions.duration);
}