添加到窗口后自动调整 UIView 的大小

发布于 2024-08-28 22:22:10 字数 903 浏览 9 评论 0原文

注意:这可能与子视图在添加到时不自动调整大小重复根视图控制器


我有一个 iPad 应用程序,可以在其主窗口中的不同视图之间切换。视图切换代码如下所示:

- (void)switchToViewController:(UIViewController*)viewController {
    if (currentViewController != viewController) {
        [currentViewController.view removeFromSuperview];
        currentViewController = viewController;
        [window addSubview:viewController.view];
    }
}

问题是,当新视图(UISplitView)以横向显示时,它的大小无法填充整个窗口。右侧有一大片空白的黑色空间。看起来视图只有 768 像素宽,而不是横向窗口的 1024 像素宽。

如果我将设备旋转到纵向然后再返回到横向,视图会自动调整大小。

如果设备处于纵向,则一切正常。如果 UISplitView 是我显示的第一个视图,它的大小也会正确调整。仅当我在横向显示另一个视图后切换到它时,才会出现此问题。

那么,有什么方法可以强制 iPhone OS 在将视图添加到窗口后调整视图大小吗?

我尝试调用 sizeToFitsetNeedsLayout。我还尝试将视图的边界设置为窗口的边界,并且尝试设置框架以匹配前一个视图的框架。

Note: This may be a duplicate of Subview Doesnt AutoSize When Added to Root View Controller


I have an iPad app that switches between different views in its main window. The view-switching code looks like this:

- (void)switchToViewController:(UIViewController*)viewController {
    if (currentViewController != viewController) {
        [currentViewController.view removeFromSuperview];
        currentViewController = viewController;
        [window addSubview:viewController.view];
    }
}

The problem is that when the new view (a UISplitView) appears in landscape orientation, it is not sized to fill the entire window. There is a large empty black space on the right. It looks like the view is only 768 pixels wide, rather than the 1024-pixel width of the landscape window.

If I rotate the device to portrait and then back to landscape, the view sizes itself properly.

If the device is in portrait orientation, everything works fine. The UISplitView also gets sized properly if it is the first view I show. The problem only occurs if I switch to it after another view has been shown, in landscape.

So, is there some way to force iPhone OS to resize the view after it has been added to the window?

I've tried calling sizeToFit, and setNeedsLayout. I've also tried setting the view's bounds to the window's bounds, and I've tried setting the frame to match the previous view's frame.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

风轻花落早 2024-09-04 22:22:10

这绝对是可能的! :-)

你可以在这里查看我的存储库:
https://github.com/hfossli/AGWindowView

它会自动处理任何旋转和帧更改,这样你就赢了不必担心这个。

如果您想担心这一点,那么您可以剪切并粘贴最重要的部分

# 1 将视图添加到窗口

[[UIApplication sharedApplication] keyWindow] addSubview:aView];

# 2 添加侦听器并更新视图

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameOrOrientationChanged:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameOrOrientationChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];

请记住删除通知侦听

[[NSNotificationCenter defaultCenter] removeObserver:self];

# 3 做数学题

- (void)statusBarFrameOrOrientationChanged:(NSNotification *)notification
{
    /*
     This notification is most likely triggered inside an animation block,
     therefore no animation is needed to perform this nice transition.
     */
    [self rotateAccordingToStatusBarOrientationAndSupportedOrientations];
}

- (void)rotateAccordingToStatusBarOrientationAndSupportedOrientations
{
    UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
    CGFloat angle = UIInterfaceOrientationAngleOfOrientation(statusBarOrientation);
    CGFloat statusBarHeight = [[self class] getStatusBarHeight];

    CGAffineTransform transform = CGAffineTransformMakeRotation(angle);
    CGRect frame = [[self class] rectInWindowBounds:self.window.bounds statusBarOrientation:statusBarOrientation statusBarHeight:statusBarHeight];

    [self setIfNotEqualTransform:transform frame:frame];
}

- (void)setIfNotEqualTransform:(CGAffineTransform)transform frame:(CGRect)frame
{
    if(!CGAffineTransformEqualToTransform(self.transform, transform))
    {
        self.transform = transform;
    }
    if(!CGRectEqualToRect(self.frame, frame))
    {
        self.frame = frame;
    }
}

+ (CGFloat)getStatusBarHeight
{
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    if(UIInterfaceOrientationIsLandscape(orientation))
    {
        return [UIApplication sharedApplication].statusBarFrame.size.width;
    }
    else
    {
        return [UIApplication sharedApplication].statusBarFrame.size.height;
    }
}

+ (CGRect)rectInWindowBounds:(CGRect)windowBounds statusBarOrientation:(UIInterfaceOrientation)statusBarOrientation statusBarHeight:(CGFloat)statusBarHeight
{    
    CGRect frame = windowBounds;
    frame.origin.x += statusBarOrientation == UIInterfaceOrientationLandscapeLeft ? statusBarHeight : 0;
    frame.origin.y += statusBarOrientation == UIInterfaceOrientationPortrait ? statusBarHeight : 0;
    frame.size.width -= UIInterfaceOrientationIsLandscape(statusBarOrientation) ? statusBarHeight : 0;
    frame.size.height -= UIInterfaceOrientationIsPortrait(statusBarOrientation) ? statusBarHeight : 0;
    return frame;
}

CGFloat UIInterfaceOrientationAngleOfOrientation(UIInterfaceOrientation orientation)
{
    CGFloat angle;

    switch (orientation)
    {
        case UIInterfaceOrientationPortraitUpsideDown:
            angle = M_PI;
            break;
        case UIInterfaceOrientationLandscapeLeft:
            angle = -M_PI_2;
            break;
        case UIInterfaceOrientationLandscapeRight:
            angle = M_PI_2;
            break;
        default:
            angle = 0.0;
            break;
    }

    return angle;
}

UIInterfaceOrientationMask UIInterfaceOrientationMaskFromOrientation(UIInterfaceOrientation orientation)
{
    return 1 << orientation;
}

祝你好运!

This is absolutely possible! :-)

You can check out my repo here:
https://github.com/hfossli/AGWindowView

It will automatically deal with any rotation and framechanges so you won't have to worry about that.

If you like to worry about that then you can just cut and paste the most important parts

# 1 Add view to window

[[UIApplication sharedApplication] keyWindow] addSubview:aView];

# 2 Add listener and update view

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameOrOrientationChanged:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarFrameOrOrientationChanged:) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];

Remember to remove notification listening

[[NSNotificationCenter defaultCenter] removeObserver:self];

# 3 Do the math

- (void)statusBarFrameOrOrientationChanged:(NSNotification *)notification
{
    /*
     This notification is most likely triggered inside an animation block,
     therefore no animation is needed to perform this nice transition.
     */
    [self rotateAccordingToStatusBarOrientationAndSupportedOrientations];
}

- (void)rotateAccordingToStatusBarOrientationAndSupportedOrientations
{
    UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
    CGFloat angle = UIInterfaceOrientationAngleOfOrientation(statusBarOrientation);
    CGFloat statusBarHeight = [[self class] getStatusBarHeight];

    CGAffineTransform transform = CGAffineTransformMakeRotation(angle);
    CGRect frame = [[self class] rectInWindowBounds:self.window.bounds statusBarOrientation:statusBarOrientation statusBarHeight:statusBarHeight];

    [self setIfNotEqualTransform:transform frame:frame];
}

- (void)setIfNotEqualTransform:(CGAffineTransform)transform frame:(CGRect)frame
{
    if(!CGAffineTransformEqualToTransform(self.transform, transform))
    {
        self.transform = transform;
    }
    if(!CGRectEqualToRect(self.frame, frame))
    {
        self.frame = frame;
    }
}

+ (CGFloat)getStatusBarHeight
{
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    if(UIInterfaceOrientationIsLandscape(orientation))
    {
        return [UIApplication sharedApplication].statusBarFrame.size.width;
    }
    else
    {
        return [UIApplication sharedApplication].statusBarFrame.size.height;
    }
}

+ (CGRect)rectInWindowBounds:(CGRect)windowBounds statusBarOrientation:(UIInterfaceOrientation)statusBarOrientation statusBarHeight:(CGFloat)statusBarHeight
{    
    CGRect frame = windowBounds;
    frame.origin.x += statusBarOrientation == UIInterfaceOrientationLandscapeLeft ? statusBarHeight : 0;
    frame.origin.y += statusBarOrientation == UIInterfaceOrientationPortrait ? statusBarHeight : 0;
    frame.size.width -= UIInterfaceOrientationIsLandscape(statusBarOrientation) ? statusBarHeight : 0;
    frame.size.height -= UIInterfaceOrientationIsPortrait(statusBarOrientation) ? statusBarHeight : 0;
    return frame;
}

CGFloat UIInterfaceOrientationAngleOfOrientation(UIInterfaceOrientation orientation)
{
    CGFloat angle;

    switch (orientation)
    {
        case UIInterfaceOrientationPortraitUpsideDown:
            angle = M_PI;
            break;
        case UIInterfaceOrientationLandscapeLeft:
            angle = -M_PI_2;
            break;
        case UIInterfaceOrientationLandscapeRight:
            angle = M_PI_2;
            break;
        default:
            angle = 0.0;
            break;
    }

    return angle;
}

UIInterfaceOrientationMask UIInterfaceOrientationMaskFromOrientation(UIInterfaceOrientation orientation)
{
    return 1 << orientation;
}

Good luck!

深白境迁sunset 2024-09-04 22:22:10

这可行,但看起来有点老套:

- (void)switchToViewController:(UIViewController *)viewController {
    if (viewController != currentViewController) {
        UIInterfaceOrientation orientation = currentViewController.interfaceOrientation;
        [currentViewController.view removeFromSuperview];

        currentViewController = viewController;
        UIView *view = viewController.view;

        // Set appropriate view frame (it won't be autosized by addSubview:)
        CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
        if (UIInterfaceOrientationIsLandscape(orientation)) {
            // Need to flip the X-Y coordinates for landscape
            view.frame = CGRectMake(appFrame.origin.y, appFrame.origin.x, appFrame.size.height, appFrame.size.width);
        }
        else {
            view.frame = appFrame;
        }

        [window addSubview:view];
    }
}

This works, but it seems a little hacky:

- (void)switchToViewController:(UIViewController *)viewController {
    if (viewController != currentViewController) {
        UIInterfaceOrientation orientation = currentViewController.interfaceOrientation;
        [currentViewController.view removeFromSuperview];

        currentViewController = viewController;
        UIView *view = viewController.view;

        // Set appropriate view frame (it won't be autosized by addSubview:)
        CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
        if (UIInterfaceOrientationIsLandscape(orientation)) {
            // Need to flip the X-Y coordinates for landscape
            view.frame = CGRectMake(appFrame.origin.y, appFrame.origin.x, appFrame.size.height, appFrame.size.width);
        }
        else {
            view.frame = appFrame;
        }

        [window addSubview:view];
    }
}
回眸一笑 2024-09-04 22:22:10

除了您的视图之外,窗口可能还包含其他 UI 元素。您的示例中的 20 像素差异是状态栏的高度。

[[UIApplication sharedApplication] statusBarFrame].height;

窗口和屏幕都不旋转。仅当您切换了高度和宽度时,获取它们的框架并将它们用于旋​​转视图才有效。

如果您使用的是 UIViewController,请尝试从此方法返回 YES:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation; // Override to allow rotation. Default returns YES only for UIDeviceOrientationPortrait

The window may include other UI elements besides your view. The 20 pixel difference in your example is the height of the status bar.

[[UIApplication sharedApplication] statusBarFrame].height;

Neither the window nor screen rotate. Getting their frames and using them for a rotated view will only work if you have switched the height and width.

If you are using a UIViewController, try returning YES from this method:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation; // Override to allow rotation. Default returns YES only for UIDeviceOrientationPortrait
堇色安年 2024-09-04 22:22:10

我遇到了同样的问题,但我用这行代码修复了它:

- (void)changeRow:(NSNotification *)notification {
[window addSubview:new.view];
[old.view removeFromSuperview];
[new.view removeFromSuperview];
[window addSubview:new.view];

}

您必须添加新视图,然后删除旧视图和新视图,然后添加新视图。我不知道为什么,但这确实有效。

I got the same problem, but i fixed it with this lines of code:

- (void)changeRow:(NSNotification *)notification {
[window addSubview:new.view];
[old.view removeFromSuperview];
[new.view removeFromSuperview];
[window addSubview:new.view];

}

You must add the new view, then remove the old and the new and then add the new view. I don't know why, but that works.

っ左 2024-09-04 22:22:10

Fossli 的答案对于 iPad 来说是正确的。但是,我有一个需要支持的通用应用程序。因此,一些调整是必要的。

将以下内容添加到 AppDelegate.h

@property (strong, nonatomic) UIImageView *imageView;

将以下内容添加到 AppDelegate.m

@synthesize imageView;

- (void)orientationChanged:(NSNotification *)notification
{
    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;   
    if (! (UIInterfaceOrientationIsLandscape(deviceOrientation) ||
           UIInterfaceOrientationIsPortrait(deviceOrientation)))
    {
        // May be "UIInterfaceOrientationUnknown" which does not appear to be a defined value anywhere.
        return;
    }

    [imageView setImage:[UIImage imageNamed:[Utility getBackgroundImageNameWithOrientation:deviceOrientation]]];

    /*
     iOS Image Sizes

     iPhone/iPod    Portrait 320 x 480 (640 x 960 @2x)
     iPad           Portrait 768 x 1004 (1536 x 2008 @2x)
                    Landscape 1024 x 748 (2048 x 1496 @2x)

     iPad window bounds in both orientations 768 x 1024  (needs manual swap in landscape)
     iPhone window bounds in both orientations 320 x 480 (needs manual swap in landscape)

     Note the size variations between the required default launch image sizes and
     the size of the window bounds.
     iPhone/iPod only requires rotations.
     iPad needs origin or size adjustments depending on orientation.
     */

    CGFloat angle = 0.0;
    CGRect newFrame = [[self window] bounds];

    // How to get size of status bar
    // Size of status bar gets all wonky on rotations so just set it manually
    // CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
    CGSize statusBarSize = CGSizeMake(20.0, 20.0);

    if (deviceOrientation == UIInterfaceOrientationPortraitUpsideDown)
    {
        angle = M_PI; 
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
        {
            newFrame.size.height -= statusBarSize.height;
        }
    }
    else if (deviceOrientation == UIInterfaceOrientationLandscapeLeft)
    {
        angle = - M_PI / 2.0f;        
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
        {
            newFrame.origin.x += statusBarSize.height;
            newFrame.size.width += statusBarSize.height;
        }
    }
    else if (deviceOrientation == UIInterfaceOrientationLandscapeRight)
    {
        angle = M_PI / 2.0f;
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
        {
            newFrame.size.width -= statusBarSize.height;
        }
    }
    else
    {
        angle = 0.0;
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
        {
            newFrame.origin.y += statusBarSize.height;
            newFrame.size.height -= statusBarSize.height;
        }
    } 

    imageView.transform = CGAffineTransformMakeRotation(angle);
    imageView.frame = newFrame;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{   
    // Add background image to window with orientation changes so that it is visible in all views.
    // A listener is added since subviews do not receive orientation changes.
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object: nil];

    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;      
    imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[Utility getBackgroundImageNameWithOrientation:deviceOrientation]]];
    [[self window] addSubview:imageView];

    return YES;
}

将以下内容添加到 Utility.h

+ (NSString *)getBackgroundImageNameWithOrientation:(UIDeviceOrientation)interfaceOrientation;

将以下内容添加到 Utility.m

+ (NSString *)getBackgroundImageNameWithOrientation:(UIDeviceOrientation)interfaceOrientation
{
    NSString *imageName = nil;

    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
    {
        if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
        {
            imageName = @"Default-Landscape~ipad.png";
        }
        else
        {
            imageName = @"Default-Portrait~ipad.png";
        }
    }
    else
    {
        if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
        {
            imageName = @"Default-Landscape~iphone.png";
        }
        else
        {
            imageName = @"Default.png";
        }
    }

    return imageName;
}

Fossli's answer is correct for iPad. However, I have a universal app that I needed to support. Therefore some adjustments are necessary.

Add the following to AppDelegate.h

@property (strong, nonatomic) UIImageView *imageView;

Add the following to AppDelegate.m

@synthesize imageView;

- (void)orientationChanged:(NSNotification *)notification
{
    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;   
    if (! (UIInterfaceOrientationIsLandscape(deviceOrientation) ||
           UIInterfaceOrientationIsPortrait(deviceOrientation)))
    {
        // May be "UIInterfaceOrientationUnknown" which does not appear to be a defined value anywhere.
        return;
    }

    [imageView setImage:[UIImage imageNamed:[Utility getBackgroundImageNameWithOrientation:deviceOrientation]]];

    /*
     iOS Image Sizes

     iPhone/iPod    Portrait 320 x 480 (640 x 960 @2x)
     iPad           Portrait 768 x 1004 (1536 x 2008 @2x)
                    Landscape 1024 x 748 (2048 x 1496 @2x)

     iPad window bounds in both orientations 768 x 1024  (needs manual swap in landscape)
     iPhone window bounds in both orientations 320 x 480 (needs manual swap in landscape)

     Note the size variations between the required default launch image sizes and
     the size of the window bounds.
     iPhone/iPod only requires rotations.
     iPad needs origin or size adjustments depending on orientation.
     */

    CGFloat angle = 0.0;
    CGRect newFrame = [[self window] bounds];

    // How to get size of status bar
    // Size of status bar gets all wonky on rotations so just set it manually
    // CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
    CGSize statusBarSize = CGSizeMake(20.0, 20.0);

    if (deviceOrientation == UIInterfaceOrientationPortraitUpsideDown)
    {
        angle = M_PI; 
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
        {
            newFrame.size.height -= statusBarSize.height;
        }
    }
    else if (deviceOrientation == UIInterfaceOrientationLandscapeLeft)
    {
        angle = - M_PI / 2.0f;        
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
        {
            newFrame.origin.x += statusBarSize.height;
            newFrame.size.width += statusBarSize.height;
        }
    }
    else if (deviceOrientation == UIInterfaceOrientationLandscapeRight)
    {
        angle = M_PI / 2.0f;
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
        {
            newFrame.size.width -= statusBarSize.height;
        }
    }
    else
    {
        angle = 0.0;
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
        {
            newFrame.origin.y += statusBarSize.height;
            newFrame.size.height -= statusBarSize.height;
        }
    } 

    imageView.transform = CGAffineTransformMakeRotation(angle);
    imageView.frame = newFrame;
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{   
    // Add background image to window with orientation changes so that it is visible in all views.
    // A listener is added since subviews do not receive orientation changes.
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object: nil];

    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;      
    imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[Utility getBackgroundImageNameWithOrientation:deviceOrientation]]];
    [[self window] addSubview:imageView];

    return YES;
}

Add the following to Utility.h

+ (NSString *)getBackgroundImageNameWithOrientation:(UIDeviceOrientation)interfaceOrientation;

Add the following to Utility.m

+ (NSString *)getBackgroundImageNameWithOrientation:(UIDeviceOrientation)interfaceOrientation
{
    NSString *imageName = nil;

    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
    {
        if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
        {
            imageName = @"Default-Landscape~ipad.png";
        }
        else
        {
            imageName = @"Default-Portrait~ipad.png";
        }
    }
    else
    {
        if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
        {
            imageName = @"Default-Landscape~iphone.png";
        }
        else
        {
            imageName = @"Default.png";
        }
    }

    return imageName;
}
寄离 2024-09-04 22:22:10

iOS7 的 Windows 与 iOS8/9 的 Windows 具有不同的行为。

iOS7 的键盘窗口和 iOS8/9 的所有窗口始终具有正确的方向和方向。尺寸。因此您可以观察尺寸变化事件并更新视图的框架。

但iOS7的其他窗口始终保持纵向方向和尺寸。旋转后您需要更新视图的变换。

您需要观察 UIApplicationWillChangeStatusBarOrientationNotification 并更新 UIView 的大小,如下所示:

@interface MyView : UIView

@end

@implementation MyView

- (instancetype)init
{
    if (self = [super init]) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeOrientationHandler:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
    }
    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
}

- (void)updateTransformWithOrientation:(UIInterfaceOrientation)orientation
{
    CGFloat width = CGRectGetWidth(self.window.bounds);
    CGFloat height = CGRectGetHeight(self.window.bounds);
    if (width > height) {
        CGFloat temp = width;
        width = height;
        height = temp;
    }
    CGFloat offset = (height - width) / 2;
    CGAffineTransform transform;
    switch (orientation) {
        case UIInterfaceOrientationLandscapeLeft:
            transform = CGAffineTransformMakeTranslation(-offset, offset);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
        case UIInterfaceOrientationLandscapeRight:
            transform = CGAffineTransformMakeTranslation(-offset, offset);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            transform = CGAffineTransformMakeRotation(-M_PI);
            break;
        default:
            transform = CGAffineTransformIdentity;
            break;
    }
    self.transform = transform;
    self.frame = CGRectMake(0, 0, width, height);
}

- (void)updateFrameWithOrientation:(UIInterfaceOrientation)orientation
{
    CGFloat width = CGRectGetWidth(self.window.bounds);
    CGFloat height = CGRectGetHeight(self.window.bounds);
    if (width > height) {
        CGFloat temp = width;
        width = height;
        height = temp;
    }
    switch (orientation) {
        case UIInterfaceOrientationLandscapeLeft:
        case UIInterfaceOrientationLandscapeRight:
            self.frame = CGRectMake(0, 0, height, width);
            break;
        default:
            self.frame = CGRectMake(0, 0, width, height);
            break;
    }
}

- (void)updateWithOrientation:(UIInterfaceOrientation)orientation
{
    BOOL isIos7 = [[UIDevice currentDevice].systemVersion floatValue] < 8.0;
    BOOL isKeyboardWindow = [self.window isKindOfClass:NSClassFromString(@"UITextEffectsWindow")];
    if (isIos7 == YES && isKeyboardWindow == NO) {
        [self updateTransformWithOrientation:orientation];
    } else {
        [self updateFrameWithOrientation:orientation];
    }
}

- (void)changeOrientationHandler:(NSNotification *)notification
{
    [UIView animateWithDuration:0.25 animations:^{
        UIInterfaceOrientation orientation = (UIInterfaceOrientation)[notification.userInfo[UIApplicationStatusBarOrientationUserInfoKey] integerValue];
        [self updateWithOrientation:orientation];
    }];
}

@end

Windows of iOS7 have different behaviors with windows of iOS8/9.

Keyboard window of iOS7 and all windows of iOS8/9 always have correct orientation & size. So you can observer the size change events and update the frame of your view.

But other windows of iOS7 always keep the portrait orientation and size. You need update transform of your view after rotation.

You need to observer UIApplicationWillChangeStatusBarOrientationNotification and update size of your UIView like this:

@interface MyView : UIView

@end

@implementation MyView

- (instancetype)init
{
    if (self = [super init]) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeOrientationHandler:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
    }
    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
}

- (void)updateTransformWithOrientation:(UIInterfaceOrientation)orientation
{
    CGFloat width = CGRectGetWidth(self.window.bounds);
    CGFloat height = CGRectGetHeight(self.window.bounds);
    if (width > height) {
        CGFloat temp = width;
        width = height;
        height = temp;
    }
    CGFloat offset = (height - width) / 2;
    CGAffineTransform transform;
    switch (orientation) {
        case UIInterfaceOrientationLandscapeLeft:
            transform = CGAffineTransformMakeTranslation(-offset, offset);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
        case UIInterfaceOrientationLandscapeRight:
            transform = CGAffineTransformMakeTranslation(-offset, offset);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            transform = CGAffineTransformMakeRotation(-M_PI);
            break;
        default:
            transform = CGAffineTransformIdentity;
            break;
    }
    self.transform = transform;
    self.frame = CGRectMake(0, 0, width, height);
}

- (void)updateFrameWithOrientation:(UIInterfaceOrientation)orientation
{
    CGFloat width = CGRectGetWidth(self.window.bounds);
    CGFloat height = CGRectGetHeight(self.window.bounds);
    if (width > height) {
        CGFloat temp = width;
        width = height;
        height = temp;
    }
    switch (orientation) {
        case UIInterfaceOrientationLandscapeLeft:
        case UIInterfaceOrientationLandscapeRight:
            self.frame = CGRectMake(0, 0, height, width);
            break;
        default:
            self.frame = CGRectMake(0, 0, width, height);
            break;
    }
}

- (void)updateWithOrientation:(UIInterfaceOrientation)orientation
{
    BOOL isIos7 = [[UIDevice currentDevice].systemVersion floatValue] < 8.0;
    BOOL isKeyboardWindow = [self.window isKindOfClass:NSClassFromString(@"UITextEffectsWindow")];
    if (isIos7 == YES && isKeyboardWindow == NO) {
        [self updateTransformWithOrientation:orientation];
    } else {
        [self updateFrameWithOrientation:orientation];
    }
}

- (void)changeOrientationHandler:(NSNotification *)notification
{
    [UIView animateWithDuration:0.25 animations:^{
        UIInterfaceOrientation orientation = (UIInterfaceOrientation)[notification.userInfo[UIApplicationStatusBarOrientationUserInfoKey] integerValue];
        [self updateWithOrientation:orientation];
    }];
}

@end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文