MGLMapView setCamera( <camera fitting content>() ) doesn't work correctly with MGLMapView.contentInset
Following methods:
- (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds;
- (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets;
- (MGLMapCamera *)camera:(MGLMapCamera *)camera fittingCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)insets;
- (MGLMapCamera *)camera:(MGLMapCamera *)camera fittingShape:(MGLShape *)shape edgePadding:(UIEdgeInsets)insets;
- (MGLMapCamera *)cameraThatFitsShape:(MGLShape *)shape direction:(CLLocationDirection)direction edgePadding:(UIEdgeInsets)insets;
use currently set MGLMapView.contentInset when computing camera that would fit desired content to an area defined by MGLMapView.contentInset + optional padding, as if contentInset in MGLMapView would not additionally move the content when
setting this camera using any of following
@property (nonatomic, copy) MGLMapCamera *camera;
- (void)setCamera:(MGLMapCamera *)camera animated:(BOOL)animated;
- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function;
- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion;
- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function edgePadding:(UIEdgeInsets)edgePadding completionHandler:(nullable void (^)(void))completion;
- (void)flyToCamera:(MGLMapCamera *)camera completionHandler:(nullable void (^)(void))completion;
- (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration completionHandler:(nullable void (^)(void))completion;
- (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration peakAltitude:(CLLocationDistance)peakAltitude completionHandler:(nullable void (^)(void))completion;
As a result we get double contentInset applied.
Workaround:
set view contentInset to .zero (set automaticallyAdjustsScrollViewInsets to false) and supply desired padding to
contentInset = .zero
let camera = cameraThatFitsShape(line, direction: direction, edgePadding: safeArea)
setCamera(camera, animated: animated)
I agree that there’s a difference in behavior between the -camera… getters and the -setCamera… setters and that it’s confusing and unexpected. To be clear, the desired behavior is that the getters’ use of content insets cancel out the setters’ use of content insets. For example, this code should have no effect even when there’s a content inset:
mapView.camera = mapView.camera
equivalently:
[mapView setCamera:[mapView camera]];
At the same time, if you pass the return value of -cameraThatFitsCoordinateBounds:edgePadding: into -setCamera:withDuration:animationTimingFunction:edgePadding:completionHandler:, you would have to pass the same edge padding into both methods in order for the -cameraThatFitsCoordinateBounds:edgePadding: return value to be accurate. At least that’s how I’d expect the methods to behave based on their naming.
I spended near 8h try to resolve bug related to this behaviour
@1ec5 thanks for clarifying, it's unfortunate that this part of the API is a often misunderstood. Finding these illuminating threads sure feels like collecting golden nuggets.
I am currently setting my camera with the following to prevent any sudden jumps:
mapView.setCamera(
mapView.camera(
mapView.camera,
fitting: .init(
center: center,
distance: 1000 // meters
),
edgePadding: padding // matching padding
),
withDuration: 1,
animationTimingFunction: nil,
edgePadding: padding, // matching padding
completionHandler: nil
)
Sometimes, though, the edgePadding is not preserved and the camera jumps. Could you suggest some way to fix this? It happens when the user changes the map zoom level by panning. It looks like this resets the edgePadding on the camera, and setting a camera with added edge padding again will cause it's viewport to jump.