2010-04-17 29 views
6

Lưu ý: Đây có thể là một bản sao của Subview Doesnt AutoSize When Added to Root View ControllerTự động Cắt tinh UIView sau Thêm vào Window


Tôi có một ứng dụng iPad mà chuyển đổi giữa quan điểm khác nhau trong cửa sổ chính của nó. Mã xem chuyển mạch trông như thế này:

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

Vấn đề là khi quan điểm mới (một UISplitView) xuất hiện trong định hướng phong cảnh, nó không phải là kích thước để lấp đầy toàn bộ cửa sổ. Có một khoảng trống lớn màu đen ở bên phải. Có vẻ như chế độ xem chỉ rộng 768 pixel, thay vì chiều rộng 1024 pixel của cửa sổ ngang.

Nếu tôi xoay thiết bị theo chiều dọc và sau đó quay lại ngang, chế độ xem sẽ tự kích thước chính xác.

Nếu thiết bị ở hướng dọc, mọi thứ hoạt động tốt. UISplitView cũng được kích thước đúng nếu nó là chế độ xem đầu tiên tôi hiển thị. Sự cố chỉ xảy ra nếu tôi chuyển sang vấn đề này sau khi một chế độ xem khác được hiển thị, ở chế độ ngang.

Vì vậy, có cách nào để buộc hệ điều hành iPhone thay đổi kích thước chế độ xem sau khi đã được thêm vào cửa sổ không?

Tôi đã thử gọi sizeToFitsetNeedsLayout. Tôi cũng đã thử đặt chế độ xem của bounds thành cửa sổ bounds và tôi đã thử đặt frame để khớp với khung của khung nhìn trước đó.

Trả lời

3

này hoạt động, nhưng có vẻ như một chút 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]; 
    } 
} 
+0

Bạn không gặp vấn đề ở đây, bởi vì bạn không tính 20px cho thanh điều hướng? – basti

1

Cửa sổ có thể bao gồm các yếu tố giao diện người dùng khác bên cạnh chế độ xem của bạn. Sự khác biệt 20 pixel trong ví dụ của bạn là chiều cao của thanh trạng thái.

[[UIApplication sharedApplication] statusBarFrame].height; 

Không cửa sổ cũng không xoay màn hình. Nhận khung của chúng và sử dụng chúng cho chế độ xem xoay sẽ chỉ hoạt động nếu bạn đã chuyển chiều cao và chiều rộng.

Nếu bạn đang sử dụng một UIViewController, hãy thử trở về YES từ phương pháp này:

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

Những điều này không chỉ 20 pixel tắt; chúng bị tắt 320 pixel. Tôi trả lại CÓ từ shouldAutorotateToInterfaceOrientation :, và mọi thứ hiển thị theo đúng hướng. Nó chỉ là kích thước xem là sai. –

+0

20 pixel tôi đã nói đến là ở 1004 so với 1024 và 748 so với 768. Bạn đang rời khỏi chỗ cho thanh trạng thái bằng cách mã hóa cứng giá trị 20 vào chiều rộng hoặc chiều cao của bạn. – drawnonward

1

Tôi có cùng một vấn đề, nhưng tôi đã sửa nó bằng các dòng mã sau:

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

}

Bạn phải thêm chế độ xem mới, sau đó xóa chế độ xem cũ và mới và sau đó thêm chế độ xem mới. Tôi không biết tại sao, nhưng nó hoạt động.

9

Điều này là hoàn toàn có thể! :-)

Bạn có thể kiểm tra repo của tôi ở đây: https://github.com/hfossli/AGWindowView

Nó sẽ tự động đối phó với bất kỳ luân chuyển và framechanges vì ​​vậy bạn sẽ không phải lo lắng về điều đó.

Nếu bạn thích phải lo lắng về điều đó sau đó bạn chỉ có thể cắt và dán những phần quan trọng nhất

# 1 Add nhằm cửa sổ

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

# 2 Thêm người nghe và cập nhật xem

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

Hãy nhớ xóa thông báo đang nghe

[[NSNotificationCenter defaultCenter] removeObserver:self]; 

# 3 Làm toán

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

Chúc may mắn!

1

Câu trả lời của Fossli là chính xác cho iPad. Tuy nhiên, tôi có một ứng dụng toàn cầu mà tôi cần hỗ trợ. Do đó một số điều chỉnh là cần thiết.

Thêm dòng sau vào AppDelegate.h

@property (strong, nonatomic) UIImageView *imageView; 

Thêm dòng sau vào 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; 
} 

Thêm dòng sau vào Utility.h

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

Thêm dòng sau vào Tiện ích.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

Cũng lưu ý rằng nếu bạn không hiển thị thanh trạng thái cho ứng dụng của mình (và có lẽ bạn nên), bạn có thể không cần một số điều chỉnh bằng cách sử dụng chiều cao của thanh trạng thái. – Christopher

0

Windows của iOS7 có các hành vi khác nhau với các cửa sổ iOS8/9.

Cửa sổ bàn phím của iOS7 và tất cả cửa sổ iOS8/9 luôn có định hướng đúng kích thước &. Vì vậy, bạn có thể quan sát các sự kiện thay đổi kích thước và cập nhật khung của chế độ xem của bạn.

Nhưng các cửa sổ khác của iOS7 luôn giữ hướng và kích thước dọc. Bạn cần cập nhật biến đổi chế độ xem của mình sau khi xoay.

Bạn cần phải UIApplicationWillChangeStatusBarOrientationNotification quan sát viên và kích thước bản cập nhật của UIView của bạn như thế này:

@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 
Các vấn đề liên quan