diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 6a36e954c5e..aa7ad42b9e8 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -6,6 +6,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Fixed a bug where setting `MGLMapView.userTrackingMode` to `MGLUserTrackingModeFollowWithHeading` or `MGLUserTrackingModeFollowWithCourse` would be ignored if the user’s location was not already available. ([#13849](https://github.com/mapbox/mapbox-gl-native/pull/13849)) * Improved tilt gesture performance. ([#13902](https://github.com/mapbox/mapbox-gl-native/pull/13902)) +* Fixed a bug where `layoutSubviews` was always called on device rotation, regardless of the application's or top-most view controller's supported orientations. ([#13900](https://github.com/mapbox/mapbox-gl-native/pull/13900)) ## 4.8.0 - January 30, 2019 diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 1483d72074d..752a1a780b0 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -219,6 +219,9 @@ @interface MGLMapView () 0) { + orientationMask = 0; + + NSDictionary *lookup = + @{ + @"UIInterfaceOrientationPortrait" : @(UIInterfaceOrientationMaskPortrait), + @"UIInterfaceOrientationPortraitUpsideDown" : @(UIInterfaceOrientationMaskPortraitUpsideDown), + @"UIInterfaceOrientationLandscapeLeft" : @(UIInterfaceOrientationMaskLandscapeLeft), + @"UIInterfaceOrientationLandscapeRight" : @(UIInterfaceOrientationMaskLandscapeRight) + }; + + for (NSString *orientation in orientations) { + UIInterfaceOrientationMask mask = ((NSNumber*)lookup[orientation]).unsignedIntegerValue; + orientationMask |= mask; + } + } + }); + + self.applicationSupportedInterfaceOrientations = orientationMask; +} + - (void)deviceOrientationDidChange:(__unused NSNotification *)notification { + UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation]; + + // The docs for `UIViewController.supportedInterfaceOrientations` states: + // + // When the user changes the device orientation, the system calls this method + // on the root view controller or the topmost presented view controller that + // fills the window. If the view controller supports the new orientation, the + // window and view controller are rotated to the new orientation. This method + // is only called if the view controller'€™s shouldAutorotate method returns YES. + // + // We want to match similar behaviour. However, it may be preferable to look + // at the owning view controller (in cases where the map view may be covered + // by another view. + + UIViewController *viewController = [self.window.rootViewController mgl_topMostViewController]; + + if (![viewController shouldAutorotate]) { + return; + } + + if ((self.currentOrientation == (UIInterfaceOrientation)deviceOrientation) && + (self.currentOrientation != UIInterfaceOrientationUnknown)) { + return; + } + + // "The system intersects the view controller'€™s supported orientations with + // the app's supported orientations (as determined by the Info.plist file or + // the app delegate's application:supportedInterfaceOrientationsForWindow: + // method) and the device's supported orientations to determine whether to rotate. + + UIInterfaceOrientationMask supportedOrientations = viewController.supportedInterfaceOrientations; + supportedOrientations &= self.applicationSupportedInterfaceOrientations; + + // Interface orientations are defined by device orientations + UIInterfaceOrientationMask interfaceOrientation = 1 << deviceOrientation; + UIInterfaceOrientationMask validOrientation = interfaceOrientation & UIInterfaceOrientationMaskAll; + + if (!(validOrientation & supportedOrientations)) { + return; + } + + self.currentOrientation = (UIInterfaceOrientation)deviceOrientation; + + // Q. Do we need to re-layout if we're just going from Portrait -> Portrait + // Upside Down (or from Left to Right)? [self setNeedsLayout]; }