ios xcode interface-builder xib screen-orientation

Diseños alternativos de iOS para retrato y paisaje con solo un archivo.xib



xcode interface-builder (8)

Usando el constructor de interfaz en xcode y solo un archivo .xib, ¿cómo puedo crear diseños alternativos cuando giro entre las orientaciones horizontal y vertical?

Ver diagrama de diferentes diseños

Nb . la vista / área verde contendría 3 elementos que fluyen horizontalmente en el paisaje y en vertical esos 3 elementos fluirían verticalmente dentro de la vista / área verde.


Me gusta la solución de @MeXx, pero tiene la ventaja de mantener dos jerarquías de vistas diferentes en la memoria. Además, si alguna subvista tiene un estado (por ejemplo, color) que cambia, tendrá que mapearla cuando cambie de jerarquía.

Otra solución podría ser utilizar el diseño automático y cambiar las restricciones para cada subvista para cada orientación. Esto funcionaría mejor si tiene un mapeo 1: 1 entre las subvistas en ambas orientaciones.

Es comprensible que quiera usar IB para definir visualmente el diseño para cada orientación. Según mi plan, tendrías que hacer lo que prescribe @MeXx, pero luego crear un mecanismo para almacenar ambos conjuntos de restricciones una vez que se cargó el plumín ( awakeFromNib ) y volver a aplicar el conjunto correcto en el diseño ( viewWillLayoutSubviews ). Podrías tirar la jerarquía de vista secundaria una vez que raspaste y almacenaras sus restricciones. (Debido a que las restricciones son específicas de la vista, es probable que esté creando nuevas restricciones para aplicarlas a las subvistas reales).

Lo siento, no tengo ningún código. Es solo un plan en esta etapa.

Nota final: todo sería más fácil con un xib que con un guión gráfico, ya que en un guión gráfico es doloroso describir vistas que viven fuera de la vista principal del controlador de vista (lo cual es deseable ya que de lo contrario es un PITA para editar). Blach!


Me gustaría agregar una nueva respuesta para reflejar las nuevas funciones en ios8 y XCode 6.

En el último software nuevo, Apple introdujo las clases de tamaño , que permiten que el guión gráfico se adapte de manera inteligente en función del tamaño de la pantalla y la orientación que está utilizando. Aunque sugiero que mires los documentos anteriores o la sesión de la WWDC 2014 creando aplicaciones adaptativas con UIKit , intentaré parafrasear.

Asegúrese de que las clases de tamaño estén habilitadas,.

Notarás que tus archivos del guión gráfico ahora son cuadrados. Puede configurar la interfaz básica aquí. La interfaz se redimensionará de forma inteligente para todos los dispositivos habilitados y la orientación.

En la parte inferior de la pantalla, verá un botón que dice YAny xAny. Al hacer clic aquí, puede modificar solo una clase de tamaño, por ejemplo, horizontal y vertical.

Sugiero que lea los documentos anteriores, pero espero que esto lo ayude, ya que usa solo un guión gráfico.


No hay una manera automática de respaldar eso ya que va en contra del diseño de Apple. Debería tener un ViewController que admita ambas orientaciones.

Pero si realmente quiere hacerlo, debe volver a cargar xib en eventos de rotación y cargar diferentes archivos semilla.

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [[NSBundle mainBundle] loadNibNamed:[self nibNameForInterfaceOrientation:toInterfaceOrientation] owner:self options:nil]; [self viewDidLoad]; } - (NSString*) nibNameForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { NSString *postfix = (UIInterfaceOrientationIsLandscape(interfaceOrientation)) ? @"portrait" : @"landscape"; return [NSString stringWithFormat:@"%@-%@", NSStringFromClass([self class]), postfix]; }

Y crea dos archivos de punta fijados con "paisaje" y "retrato".


Puede usar la biblioteca GPOrientation. Aquí hay un enlace


Solución con guión gráfico [ios7]. Dentro del controlador de vista principal, está la vista de contenedor que puede incluir el controlador de la barra de pestañas. Dentro del controlador de la barra de pestañas, hay 2 pestañas. Una pestaña es para controlador con retrato y otra para controlador en modo paisaje.

El controlador de vista principal implementa estas funciones:

#define INTERFACE_ORIENTATION() ([[UIApplication sharedApplication]statusBarOrientation]) @interface MainViewController () @property(nonatomic,weak) UITabBarController *embeddedTabBarController; @end @implementation MainViewController - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"embedContainer"]) { self.embeddedTabBarController = segue.destinationViewController; [self.embeddedTabBarController.tabBar setHidden:YES]; } } - (void) adaptToOrientation:(UIInterfaceOrientation)interfaceOrientation { if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) { [self.embeddedTabBarController setSelectedIndex:1]; } else { [self.embeddedTabBarController setSelectedIndex:0]; } } - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { [self adaptToOrientation:interfaceOrientation]; } - (void) viewWillAppear:(BOOL)animated { [self adaptToOrientation:INTERFACE_ORIENTATION()]; }

El enlace segue en el guión gráfico debe llamarse "embedContainer".

Asegúrese de que la vista del contenedor se pueda cambiar de tamaño para cumplir con la vista principal, en ambos casos, horizontal y vertical.

Tenga cuidado con el hecho de que en el tiempo de ejecución 2 instancias del mismo controlador viven en el mismo tiempo.

Actualización: Apple docs para controlador de vista de paisaje alternativo


Una forma de hacerlo es tener tres vistas en su archivo .xib. La primera es la vista normal de su Viewcontroller sin subvistas.

Luego, crea las vistas para vertical y horizontal a medida que las necesita. Las tres tienen que ser vistas de nivel raíz (eche un vistazo a la captura de pantalla)

En su Viewcontroller, cree 2 IBOutlets, uno para el retrato y otro para la vista de paisaje y conéctelos con las vistas correspondientes en el constructor de interfaz:

IBOutlet UIView *_portraitView; IBOutlet UIView *_landscapeView; UIView *_currentView;

La tercera vista, _currentView , es necesaria para realizar un seguimiento de cuál de estas vistas se muestra actualmente. Luego crea una nueva función como esta:

-(void)setUpViewForOrientation:(UIInterfaceOrientation)orientation { [_currentView removeFromSuperview]; if(UIInterfaceOrientationIsLandscape(orientation)) { [self.view addSubview:_landscapeView]; _currentView = _landscapeView; } else { [self.view addSubview:_portraitView]; _currentView = _portraitView; } }

Tendrá que llamar a esta función desde dos lugares diferentes, primero para la inicialización:

-(void)viewDidLoad { [super viewDidLoad]; UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation]; [self setUpViewForOrientation:interfaceOrientation]; }

Y segundo para los cambios de orientación:

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

Espero que te ayude!


Ya puedes señor, seguramente ...

Lo que solía hacer es dar marco manualmente cuando el dispositivo gira

Cuando el dispositivo gira, - (void)viewWillLayoutSubviews se llama a - (void)viewWillLayoutSubviews

por ejemplo: tome un UIButton *button en su UIView ,

- (void)viewWillLayoutSubviews { if (UIDeviceOrientationIsLandscape([self.view interfaceOrientation])) { //x,y as you want [ button setFrame:CGRectMake:(x,y,button.width,button.height)]; } else { //In potrait //x,y as you want [ button setFrame:CGRectMake:(x,y,button.width,button.height)]; } }

De esta manera puedes colocarlo como quieras. Gracias

Por favor, eche un vistazo a estas imágenes

Primera imagen de mi xCode XIB UIView que quiero en ambas pantallas

Ahora, como también quiero ver esta vista en el paisaje, fui a editar mi -(void)viewWillLayoutSubviews

Ahora el resultado es como esta Primera imagen de pantalla potrait en simulador

y esto está en Landscape


Cambiar el tamaño de forma programática

Tengo una aplicación donde tengo exactamente la misma situación. En mi NIB solo tengo el diseño de retrato. El otro diseño se realiza programáticamente. No es tan difícil especificar algunos tamaños mediante programación, por lo que no es necesario mantener dos NIB.

Tenga en cuenta que realizar la vista cambiar programáticamente configurando marcos dará como resultado una animación (o puede hacerse fácilmente mediante una animación). Esto le dará al usuario una retroalimentación valiosa sobre qué componente se movió a qué posición. Si solo carga una segunda vista, perderá esta ventaja y, desde la perspectiva de la interfaz de usuario, creo que cargar una vista alternativa no es una buena solución.

Use dos ViewControllers

Si desea utilizar dos ViewControllers, Apple describe cómo hacerlo en su documentación de desarrollador, es decir, encuentra la respuesta a su pregunta aquí: RespondingtoDeviceOrientationChanges .

Si desea hacerlo programáticamente, puede agregar código de didRotateFromInterfaceOrientation en el método didRotateFromInterfaceOrientation .

Ejemplo

Agregué el método a mi ViewController:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [self adjustLayoutToOrientation]; }

Luego implementó el ajuste del diseño. Aquí hay un ejemplo (el código es específico de mi aplicación, pero puede leer los tamaños de las supervistas y calcular los marcos de las subvistas a partir de él).

- (void)adjustLayoutToOrientation { UIInterfaceOrientation toInterfaceOrientation = self.interfaceOrientation; bool isIPhone = !([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] && [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad); [self adjustViewHeight]; [self adjustSubviewsToFrame: [mailTemplateBody.superview.superview frame]]; CGRect pickerViewWrapperFrame = pickerViewWrapper.frame; if(isIPhone) { pickerViewWrapperFrame.origin.x = 0; pickerViewWrapperFrame.size.height = keyboardHeight; pickerViewWrapperFrame.origin.y = [self view].frame.size.height-pickerViewWrapperFrame.size.height; pickerViewWrapperFrame.size.width = [self view].frame.size.width; } else { pickerViewWrapperFrame = pickerView.frame; } // MORE ADJUSTMENTS HERE }