2010-04-17 113 views
6

注后自动设定其大小的UIView:这可能是Subview Doesnt AutoSize When Added to Root View Controller添加到窗口


重复我有一个iPad应用程序,在其主窗口不同意见之间切换。视认切换代码如下所示:

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

的问题是,当新的视图(一UISplitView)出现在横向,它不是大小以填满整个窗口。右侧有一个很大的空白区域。它看起来像视图只有768个像素宽,而不是横向窗口的1024像素宽度。

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

如果设备是纵向的,一切工作正常。如果它是我展示的第一个视图,则UISplitView也可以正确调整大小。只有在横向显示另一个视图后切换到该视图时,才会出现此问题。

那么,有没有办法迫使iPhone操作系统在添加到窗口后调整视图的大小?

我试过拨打sizeToFitsetNeedsLayout。我也尝试将视图的bounds设置为窗口的bounds,并且我尝试将frame设置为与先前视图的框架相匹配。

回答

3

这工作,但似乎有点哈克:

- (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]; 
    } 
} 
+0

难道你不会在这里遇到问题,因为你不计算导航栏的20像素? – basti 2012-03-05 13:35:41

1

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

[[UIApplication sharedApplication] statusBarFrame].height; 

窗口和屏幕都不旋转。获取其框架并将它们用于旋​​转视图将仅在切换高度和宽度时才起作用。

如果您正在使用一个UIViewController,尝试从这个方法返回YES:

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

事情并不只是20个像素脱落;他们是320个像素关闭。 我从shouldAutorotateToInterfaceOrientation返回YES,并且所有内容都显示为正确的方向。这只是视图大小是错误的。 – 2010-04-17 23:55:23

+0

我说的20像素是在1004 vs 1024和748 vs 768中。通过将值20硬编码为宽度或高度,您将为状态栏留出空间。 – drawnonward 2010-04-18 05:13:14

1

我得到了同样的问题,但我

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

}

:与此行代码固定它

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

9

这绝对有可能! :-)

您可以检查出我的回购在这里: https://github.com/hfossli/AGWindowView

它会自动与旋转和framechanges处理,所以你不必担心。

如果你喜欢担心那么你可以剪切和

#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; 
} 

祝你好运!

1

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; 
} 
+0

另外请注意,如果你没有显示你的应用的状态栏(你可能应该),你可能不需要使用状态栏高度进行一些调整。 – Christopher 2012-06-12 20:31:56

0

iOS7的窗口与iOS8/9的窗口有不同的行为。

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