summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Rex <julian.rex@gmail.com>2019-02-11 23:07:15 -0500
committerGitHub <noreply@github.com>2019-02-11 23:07:15 -0500
commit2deebc0efe58778d42a021b817f31535ca00016d (patch)
treef7525aafe9fb8d0636dcfe2bdbed0e71d6bf1b4f
parent57438c2a7e2f7da1db386faef846cdbf121928fa (diff)
downloadqtlocation-mapboxgl-2deebc0efe58778d42a021b817f31535ca00016d.tar.gz
[ios] Check supported interface orientations when rotating device/view layout (#13900)
-rw-r--r--platform/ios/CHANGELOG.md1
-rw-r--r--platform/ios/src/MGLMapView.mm101
2 files changed, 101 insertions, 1 deletions
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 6a36e954c5..aa7ad42b9e 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 1483d72074..752a1a780b 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -219,6 +219,9 @@ public:
@property (nonatomic) UILongPressGestureRecognizer *quickZoom;
@property (nonatomic) UIPanGestureRecognizer *twoFingerDrag;
+@property (nonatomic) UIInterfaceOrientation currentOrientation;
+@property (nonatomic) UIInterfaceOrientationMask applicationSupportedInterfaceOrientations;
+
@property (nonatomic) MGLCameraChangeReason cameraChangeReasonBitmask;
/// Mapping from reusable identifiers to annotation images.
@@ -609,10 +612,12 @@ public:
// so causes a loop when asking for location permission. See: https://github.com/mapbox/mapbox-gl-native/issues/11225
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
+
+ // Device orientation management
+ self.currentOrientation = UIInterfaceOrientationUnknown;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
-
// set initial position
//
mbgl::CameraOptions options;
@@ -1287,6 +1292,11 @@ public:
[self updateDisplayLinkPreferredFramesPerSecond];
}
+- (void)willMoveToWindow:(UIWindow *)newWindow {
+ [super willMoveToWindow:newWindow];
+ [self refreshSupportedInterfaceOrientationsWithWindow:newWindow];
+}
+
- (void)didMoveToWindow
{
[self validateDisplayLink];
@@ -1299,8 +1309,97 @@ public:
[super didMoveToSuperview];
}
+- (void)refreshSupportedInterfaceOrientationsWithWindow:(UIWindow *)window {
+
+ // "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.
+
+ UIApplication *application = [UIApplication sharedApplication];
+
+ if (window && [application.delegate respondsToSelector:@selector(application:supportedInterfaceOrientationsForWindow:)]) {
+ self.applicationSupportedInterfaceOrientations = [application.delegate application:application supportedInterfaceOrientationsForWindow:window];
+ return;
+ }
+
+ // If no delegate method, check the application's plist.
+ static UIInterfaceOrientationMask orientationMask = UIInterfaceOrientationMaskAll;
+
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ // No application delegate
+ NSArray *orientations = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UISupportedInterfaceOrientations"];
+
+ // Application's info plist provided supported orientations.
+ if (orientations.count > 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];
}