2010-05-12 22 views
34

Esta es una pregunta más general para que la gente me brinde orientación, básicamente estoy aprendiendo el desarrollo de iPad/iPhone y finalmente me he topado con la pregunta de soporte de orientación múltiple.manejo de orientación de iphone/ipad

He buscado una buena cantidad de doco, y mi libro "Beginning iPhone 3 Development" tiene un bonito capítulo sobre él.

Pero mi pregunta es esta, si tuviera que cambiar programáticamente mis controles (o incluso usar diferentes vistas para cada orientación) cómo diablos las personas mantienen su código base? Me imagino tantos problemas con el código de spaghetti/miles de controles "si" por todas partes, que me volvería loco hacer un pequeño cambio en el arreglo de UI.

¿Alguien tiene experiencia en el manejo de este problema? ¿Cuál es una buena forma de controlarlo?

Muchas gracias Marcos

Respuesta

41

Puedo hacer esto con dos métodos simples en mi controlador de vista:

- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { 
    [self adjustViewsForOrientation:toInterfaceOrientation]; 
} 

- (void) adjustViewsForOrientation:(UIInterfaceOrientation)orientation { 
    if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) { 
     titleImageView.center = CGPointMake(235.0f, 42.0f); 
     subtitleImageView.center = CGPointMake(355.0f, 70.0f); 
     ... 
    } 
    else if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) { 
     titleImageView.center = CGPointMake(160.0f, 52.0f); 
     subtitleImageView.center = CGPointMake(275.0f, 80.0f); 
     ... 
    } 
} 

Para mantener este limpia fácilmente se podría compartimentar la vista ajustes/recarga/etc. con métodos llamados desde el único condicional if-else.

+0

sí, esto es algo así como lo que estoy haciendo ahora ... gracias – Mark

+1

el método willRotateToInterface para mí nunca se está llamando. ¿Tienes que conectar algo o agregar un oyente en IB o algo así? –

+0

este es un gran ejemplo que estaba buscando. algún ejemplo alternativo? –

2

El iPhone SDK está construida en torno a tener una arquitectura MVC, así que en teoría si se mantiene toda su lógica (modelo) separado de la interfaz de usuario (ver), después, sólo tendrá que preocuparse sobre la interfaz de usuario en un solo lugar: sus controladores de vista. Para ellos, podría tener un controlador de vista separado para cada orientación, cada uno de los cuales se cargaría con un if/else para elegir qué controlador de vista cargar.

La misma idea es válida para el soporte de iPhone/iPad, donde puede cargar otro controlador de visualización que puede manejar pantallas más grandes.

+0

sí, he visto a alguien hacer algo como esto, es una buena idea, gracias – Mark

7

Realmente depende de lo que está planeando.

Si mira la aplicación Configuración de Apple, puede ver que usan vistas de tabla para el diseño, con celdas personalizadas para la mayoría de las filas. Con eso, puedes permitir que una interfaz simple gire a un precio muy económico simplemente rellenando el ancho de las celdas. Esto incluso se aplica a cosas como Correo, donde hay celdas de texto de edición en cada fila. Y las tablas pueden ser transparentes, con solo botones o etiquetas visibles, para que no se vean como tablas.

Puede obtener un montón de kilometraje de la autenticación automática de cada UIView. Si tiene uno o más elementos que pueden tener una altura flexible, generalmente puede obtener un diseño de interfaz que se ve bien en cualquier orientación. Dependiendo de cómo se ve, a veces puedes simplemente fijar todo en la parte superior.

En casos excepcionales, si todos los elementos de la interfaz encajan en un cuadrado, puede simplemente rotarlos en su lugar.

Hay dos momentos en los que debe manejar explícitamente los cambios de orientación. Uno de ellos es cuando una vista se mueve de lado a lado por debajo de otro en rotación. La otra es cuando tiene diferentes imágenes para cada orientación, por ejemplo, si siempre quiere tener el ancho completo.

A veces hay formas de evitar ambos. Puede usar imágenes elásticas o limitarse a una vista por línea. O puede bloquear la orientación de ciertas vistas.

Si debe cambiar el diseño de las vistas, existe un método explícito de layoutSubviews.Deberías tratar de manejar todo tu diseño condicional en este único método. Solo se invoca cuando cambian los límites de la vista, por ejemplo, en la rotación o si ha dejado espacio para el teclado. Cree una vista personalizada para cada jerarquía de vistas que deba responder a la rotación y diseñe las subvistas desde allí.

0

no puedo dar fe de este código, y con toda honestidad por encima de la willRotateToInterfaceOrientation funciona muy bien. Aquí hay otra versión con FBDialog.m de Facebook para iphone/ipad. (Aunque, creo que esto era para una vista web)

aquí es la esencia

[[NSNotificationCenter defaultCenter] addObserver:self 
    selector:@selector(deviceOrientationDidChange:) 
    name:@"UIDeviceOrientationDidChangeNotification" object:nil]; 


- (void)deviceOrientationDidChange:(void*)object { 
    UIDeviceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 
    if ([self shouldRotateToOrientation:orientation]) { 


    CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration; 
    [UIView beginAnimations:nil context:nil]; 
    [UIView setAnimationDuration:duration]; 
    [self sizeToFitOrientation:YES]; 
    [UIView commitAnimations]; 
    } 
} 


-(CGAffineTransform)transformForOrientation { 
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 
    if (orientation == UIInterfaceOrientationLandscapeLeft) { 
    return CGAffineTransformMakeRotation(M_PI*1.5); 
    } else if (orientation == UIInterfaceOrientationLandscapeRight) { 
    return CGAffineTransformMakeRotation(M_PI/2); 
    } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) { 
    return CGAffineTransformMakeRotation(-M_PI); 
    } else { 
    return CGAffineTransformIdentity; 
    } 
} 

- (void)sizeToFitOrientation:(BOOL)transform { 
    if (transform) { 
    self.transform = CGAffineTransformIdentity; 
    } 

    CGRect frame = [UIScreen mainScreen].applicationFrame; 
    CGPoint center = CGPointMake(
    frame.origin.x + ceil(frame.size.width/2), 
    frame.origin.y + ceil(frame.size.height/2)); 

    CGFloat scale_factor = 1.0f; 
    if (FBIsDeviceIPad()) { 
    // On the iPad the dialog's dimensions should only be 60% of the screen's 
    scale_factor = 0.6f; 
    } 

    CGFloat width = floor(scale_factor * frame.size.width) - kPadding * 2; 
    CGFloat height = floor(scale_factor * frame.size.height) - kPadding * 2; 

    _orientation = [UIApplication sharedApplication].statusBarOrientation; 
    if (UIInterfaceOrientationIsLandscape(_orientation)) { 
    self.frame = CGRectMake(kPadding, kPadding, height, width); 
    } else { 
    self.frame = CGRectMake(kPadding, kPadding, width, height); 
    } 
    self.center = center; 

    if (transform) { 
    self.transform = [self transformForOrientation]; 
    } 
} 
0

En su pregunta, usted escribió:

Me puedo imaginar a tantos problemas con el código espagueti/miles de "si" comprueba por todos lados, que me volvería loco hacer un pequeño cambio en la disposición de UI.

Una forma de evitar esto es hacer una jerarquía de vista que divida desde el principio el manejo de los cambios específicos de iPhone/iPad. Solo debe establecer qué vista se carga inicialmente para cada dispositivo. Luego crea un controlador de vista como lo hace normalmente, pero también subclase el controlador de vista que ha creado. Una subclase para cada dispositivo. Ahí es donde puedes poner el código específico del dispositivo, como el manejo de la orientación. De esta manera:

MyViewController.h   // Code that is used on both devices 
    MyViewController_iPhone.h // iPhone specific code, like orientation handling 
    MyViewController_iPad.h // iPad specific code, like orientation handling 

Si usted está interesado en este enfoque, me gustaría sugerir que lea this article. Lo explica de una manera muy agradable.

Una de las cosas que el artículo menciona, es la siguiente:

--start de quote--

La belleza de este patrón es que no tienen que nuestro código basura con basura que se parece a esto:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { 
    // The device is an iPad running iPhone 3.2 or later. 
    // set up the iPad-specific view 
} else { 
    // The device is an iPhone or iPod touch. 
    // set up the iPhone/iPod Touch view 
} 

--- final de quote--

Espero que eso ayude. ¡Buena suerte!