2010-04-17 120 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