2010-04-17 8 views
6

Nota: Esto puede ser un duplicado de Subview Doesnt AutoSize When Added to Root View ControllerGRANuLOMETRÍA automáticamente UIView después de agregar a la ventana


Tengo una aplicación para iPad que permite cambiar entre diferentes puntos de vista en la ventana principal. El código de la vista-conmutación se ve así:

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

El problema es que cuando la nueva vista (un UISplitView) aparece en orientación horizontal, no está dimensionado para llenar la ventana. Hay un gran espacio negro vacío a la derecha. Parece que la vista tiene solo 768 píxeles de ancho, en lugar del ancho de 1024 píxeles de la ventana de paisaje.

Si giro el dispositivo a vertical y luego de nuevo a horizontal, la vista se dimensiona correctamente.

Si el dispositivo está en orientación vertical, todo funciona bien. El UISplitView también se dimensiona correctamente si es la primera vista que muestro. El problema solo ocurre si cambio a él después de que se haya mostrado otra vista, en el paisaje.

Entonces, ¿hay alguna manera de obligar al iPhone OS a cambiar el tamaño de la vista una vez que se haya agregado a la ventana?

He intentado llamar a sizeToFit, y setNeedsLayout. También intenté configurar el bounds de la vista en el bounds de la ventana, e intenté configurar el frame para que coincida con el marco de la vista anterior.

Respuesta

3

Esto funciona, pero parece un poco 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

¿No tiene problemas aquí, porque no calcula los 20px para la barra de navegación? – basti

1

La ventana puede incluir otros elementos de IU además de su vista. La diferencia de 20 píxeles en su ejemplo es la altura de la barra de estado.

[[UIApplication sharedApplication] statusBarFrame].height; 

Ni la ventana ni la pantalla giran. Obtener sus marcos y usarlos para una vista rotativa solo funcionará si ha cambiado el alto y el ancho.

Si está utilizando un UIViewController, intente volver SÍ de este método:

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

las cosas no son tan sólo 20 píxeles fuera; tienen 320 píxeles de descuento. Estoy devolviendo SÍ de shouldAutorotateToInterfaceOrientation :, y todo se muestra en la orientación correcta. Es solo el tamaño de la vista lo que está mal. –

+0

Los 20 píxeles que estaba hablando estaban en 1004 vs 1024 y 748 vs 768. Está dejando espacio para la barra de estado al codificar el valor 20 en su ancho o alto. – drawnonward

1

Tengo el mismo problema, pero yo fijo con estas líneas de código:

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

}

Debe agregar la nueva vista, luego eliminar la antigua y la nueva y luego agregar la nueva vista. No sé por qué, pero eso funciona.

9

¡Esto es absolutamente posible! :-)

Se puede extraer de mi repo aquí: https://github.com/hfossli/AGWindowView

Se ocupará automáticamente con cualquier rotación y framechanges por lo que no tendrá que preocuparse por eso.

Si te gusta que preocuparse por eso a continuación, puedes cortar y pegar las partes más importantes

# 1 Añadir vista a la ventana

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

# 2 Agregar oyente y actualización de vista

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

Recuerde eliminar la notificación de escucha

[[NSNotificationCenter defaultCenter] removeObserver:self]; 

# 3 Hacer los cálculos

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

Buena suerte!

1

La respuesta de Fossli es correcta para iPad. Sin embargo, tengo una aplicación universal que necesitaba para apoyar. Por lo tanto, algunos ajustes son necesarios.

Agregue lo siguiente al AppDelegate.h

@property (strong, nonatomic) UIImageView *imageView; 

Añadir lo siguiente a 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; 
} 

Añadir lo siguiente a Utility.h

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

Añadir lo siguiente a 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

También tenga en cuenta que si no muestra la barra de estado para su aplicación (y probablemente debería hacerlo) puede que no necesite algunos de los ajustes usando la altura de la barra de estado. – Christopher

0

Windows de iOS7 tienen comportamientos diferentes con Windows de iOS8/9.

La ventana del teclado de iOS7 y todas las ventanas de iOS8/9 siempre tienen la orientación correcta & tamaño. Entonces puede observar los eventos de cambio de tamaño y actualizar el marco de su vista.

Pero otras ventanas de iOS7 siempre mantienen la orientación vertical y el tamaño. Necesita actualizar la transformación de su vista después de la rotación.

Necesitas UIApplicationWillChangeStatusBarOrientationNotification observador y el tamaño de actualización de su UIView así:

@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 
Cuestiones relacionadas