iOS 8 / 7 UIWindow with UIWindowLevelStatusBar Rotation issue

淺唱寂寞╮ 提交于 2019-12-17 20:55:29

问题


I'm trying to add a UIWindow with UIWindowLevelStatusBar level. it works in portrait mode on ipad perfectly but after rotating device its messed up.

on iOS 7.x all rotations are fine except for upside-down, and on iOS 8.x only portrait mode is fine and all other orientations are messed up. any idea how to solve that?

CGRect frame = [UIApplication sharedApplication].statusBarFrame;
self.statusWindow = [[UIWindow alloc] initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, 20)];

UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
CGRect frame = [UIApplication sharedApplication].statusBarFrame;
CGAffineTransform test = [self transformForOrientation:orientation];

[self.statusWindow setWindowLevel:UIWindowLevelStatusBar];
[self.statusWindow setHidden:NO];


- (CGAffineTransform)transformForOrientation:(UIInterfaceOrientation)orientation
{
 switch (orientation)
 {
    case UIInterfaceOrientationLandscapeLeft:
        return CGAffineTransformMakeRotation(-DEGREES_TO_RADIANS(90.0f));

    case UIInterfaceOrientationLandscapeRight:
        return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(90.0f));

    case UIInterfaceOrientationPortraitUpsideDown:
        return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(180.0f));

    case UIInterfaceOrientationPortrait:
    default:
        return CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0.0f));
}
}

回答1:


In your UIWindow subclass' init method, observe this notification:

// Rotation Notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeOrientation:) name:UIDeviceOrientationDidChangeNotification object:nil];

self.baseT = self.transform;

Then the method itself:

- (void)didChangeOrientation:(NSNotification *)n
{

    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;

    switch (orientation) {
        case UIInterfaceOrientationPortrait:
            self.transform = CGAffineTransformRotate(self.baseT, 0);
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            self.transform = CGAffineTransformRotate(self.baseT, M_PI);
            break;
//      Home button on left
        case UIInterfaceOrientationLandscapeLeft:
            self.transform = CGAffineTransformRotate(self.baseT, -M_PI_2);
            break;
        case UIInterfaceOrientationLandscapeRight:
            self.transform = CGAffineTransformRotate(self.baseT, M_PI_2);
            break;
        default:
            self.transform = CGAffineTransformMakeRotation(0);
            break;
    }
}

Depending on your implementation, you may have to also ensure the frame doesn't change. Also, in the Class' dealloc method, stop listening to the notifications.




回答2:


As a modification to @dezinezync's answer: performing the rotation would work better if you put it in the willRotateToInterfaceOrientation method of the view controller. This way, the rotation will only be applied if the device is rotated to one of the supported orientations specified in the General -> Deployment Info section of the app's build settings. As an added bonus, you get access to the duration of the rotation animation. Just make sure you have a reference to your modal window in the view controller.

The UIDeviceOrientationDidChangeNotification notification is fired whenever the screen orientation changes, regardless of what orientations are supported. This can lead to undesireable behavior.

Here's an example:

UIWindow *modalWindow;

// Initialize your modal window somewhere in your code
// ...

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

    // Make sure the modalWindow exists
    if (modalWindow != nil)
    {
        // Animate the modal window's rotation
        [UIView animateWithDuration:duration animations:^{
            [self rotateModal:modalWindow];
        }];
    }
}

- (void)rotateModal:(UIWindow*)window
{

    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;

    switch (orientation) {
        case UIInterfaceOrientationPortrait:
            window.transform = CGAffineTransformRotate(self.baseT, 0);
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            window.transform = CGAffineTransformRotate(self.baseT, M_PI);
            break;
//      Home button on left
        case UIInterfaceOrientationLandscapeLeft:
            window.transform = CGAffineTransformRotate(self.baseT, -M_PI_2);
            break;
        case UIInterfaceOrientationLandscapeRight:
            window.transform = CGAffineTransformRotate(self.baseT, M_PI_2);
            break;
        default:
            window.transform = CGAffineTransformMakeRotation(0);
            break;
    }
}

I just did something like this on a landscape-only app, and I finally got it working properly by moving everything to the willRotateToInterfaceOrientation method.




回答3:


Solution for iOS8 (need a transform as showed above as well):

UIScreen *screen = [UIScreen mainScreen];
CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
if ([screen respondsToSelector:@selector(fixedCoordinateSpace)])
{
    [self setFrame:[screen.coordinateSpace convertRect:statusBarFrame toCoordinateSpace:screen.fixedCoordinateSpace]];
}

However it does not work for iOS9 beta.



来源:https://stackoverflow.com/questions/26976494/ios-8-7-uiwindow-with-uiwindowlevelstatusbar-rotation-issue

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!