Posicionamiento UIViewControllers en UIScrollView lado a lado

Tengo un controller de vista principal que tiene una subvista de UIScrollView y otros 2 UIViewControllers (cada uno con nibs UIView y botones). UIViewControllers 'UIView se agrega a UIScrollView usando el método addSubView. Y me gustaría poner ambos UIViewControllers lado a lado.

Tengo el siguiente código, pero parece que no funciona.

[self scrollView].pagingEnabled = YES; [self scrollView].contentSize = CGSizeMake(768 * 2, 1024); [[self scrollView] setDelegate:self]; CGRect frame1; frame1.origin.x = 0; frame1.origin.y = 0; frame1.size = CGSizeMake(768, 1024); // Model one oneView = [[OneViewController alloc] initWithNibName:@"OneViewController" bundle:nil]; //oneView.view.frame = frame1; [self.scrollView addSubview:oneView.view]; oneView.view.frame = frame1; // Model two CGRect frame2; frame2.origin.x = 768; frame2.origin.y = 0; frame2.size = CGSizeMake(768, 1024); twoView = [[TwoViewController alloc] initWithNibName:@"TwoViewController" bundle:nil]; //twoView.view.frame = frame2; [self.scrollView addSubview:twoView.view]; twoView.view.frame = frame2; 

¿Por qué oneView y twoView dentro de UIScrollView están en el mismo lugar cuando he configurado su frame.origin.x? dosView parece estar encima de oneView donde debería estar lado a lado? ¿Alguna idea de dónde lo estoy haciendo mal? ¡Gracias!

Actualización : aquí está mi código de proyecto completo en github: http://bit.ly/PLe1Le

La razón por la cual esto comenzó a suceder es que cualquier instancia de UIView que sea el valor de la propiedad de view de un UIViewController a veces recibirá un post para cambiar el tamaño de su vista a la de sus supervistas.

Específicamente, el método indocumentado viewDidMoveToWindow:shouldAppearOrDisappear: se llamará cuando se agregue una vista de controller de view a una window, como sucede al iniciar la aplicación en esta instancia. En este momento, si la instancia de view del controller de view es del tamaño de la window principal o mayor, se cambiará al tamaño del tamaño de su vista de supervisión.

El código original tomó las dos vistas que se cargaron desde el .xibs y las clasificaron a 768 * 1024, que es el tamaño de la window. Esto sucede antes de que se -makeKeyAndVisible en la window, lo que termina provocando el cambio de tamaño. Utilicé KVO en el delegado de la aplicación para ver cambiar los frameworks; aquí hay una traza de stack en el momento del cambio de tamaño:

 * thread #1: tid = 0x1f03, 0x000030f9 scroller`-[ViewController observeValueForKeyPath:ofObject:change:context:] + 105 at ViewController.m:71, stop reason = breakpoint 1.1 frame #0: 0x000030f9 scroller`-[ViewController observeValueForKeyPath:ofObject:change:context:] + 105 at ViewController.m:71 frame #1: 0x0093ad91 Foundation`NSKeyValueNotifyObserver + 345 frame #2: 0x0093a895 Foundation`NSKeyValueDidChange + 438 frame #3: 0x0092033e Foundation`-[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] + 131 frame #4: 0x009cdcb4 Foundation`_NSSetRectValueAndNotify + 187 frame #5: 0x000e1786 UIKit`-[UIViewController viewDidMoveToWindow:shouldAppearOrDisappear:] + 657 frame #6: 0x0005310c UIKit`-[UIView(Internal) _didMoveFromWindow:toWindow:] + 1040 frame #7: 0x00052edb UIKit`-[UIView(Internal) _didMoveFromWindow:toWindow:] + 479 frame #8: 0x0005d5ab UIKit`-[UIScrollView _didMoveFromWindow:toWindow:] + 65 frame #9: 0x00052edb UIKit`-[UIView(Internal) _didMoveFromWindow:toWindow:] + 479 frame #10: 0x0004f692 UIKit`-[UIView(Hierarchy) _postMovedFromSuperview:] + 158 frame #11: 0x0005446f UIKit`-[UIView(Internal) _addSubview:positioned:relativeTo:] + 1633 frame #12: 0x0004e14b UIKit`-[UIView(Hierarchy) addSubview:] + 56 frame #13: 0x0003d550 UIKit`-[UIWindow addRootViewControllerViewIfPossible] + 380 frame #14: 0x0003d670 UIKit`-[UIWindow _setHidden:forced:] + 280 frame #15: 0x0003d836 UIKit`-[UIWindow _orderFrontWithoutMakingKey] + 49 frame #16: 0x0004472a UIKit`-[UIWindow makeKeyAndVisible] + 35 frame #17: 0x00002575 scroller`-[AppDelegate application:didFinishLaunchingWithOptions:] + 661 at AppDelegate.m:21 frame #18: 0x00015386 UIKit`-[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1292 frame #19: 0x00016274 UIKit`-[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 524 frame #20: 0x00025183 UIKit`-[UIApplication handleEvent:withNewEvent:] + 1027 frame #21: 0x00025c38 UIKit`-[UIApplication sendEvent:] + 68 frame #22: 0x00019634 UIKit`_UIApplicationHandleEvent + 8196 frame #23: 0x0139eef5 GraphicsServices`PurpleEventCallback + 1274 frame #24: 0x01488195 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53 frame #25: 0x013ecff2 CoreFoundation`__CFRunLoopDoSource1 + 146 frame #26: 0x013eb8da CoreFoundation`__CFRunLoopRun + 2218 frame #27: 0x013ead84 CoreFoundation`CFRunLoopRunSpecific + 212 frame #28: 0x013eac9b CoreFoundation`CFRunLoopRunInMode + 123 frame #29: 0x00015c65 UIKit`-[UIApplication _run] + 576 frame #30: 0x00017626 UIKit`UIApplicationMain + 1163 frame #31: 0x000022ad scroller`main + 141 at main.m:16 

Podemos verificar que esto sucede porque las vistas de contenido son una instancia de vista de UIViewController al crear una instancia de una vista y agregarla al mismo time. viewDidLoad el siguiente código al final de la implementación viewDidLoad de ViewController :

 CGRect frame3 = frame2; frame3.origin.x = 768.0f * 2.0f; UIView *thirdView = [[UIView alloc] initWithFrame:frame3]; [thirdView setBackgroundColor:[UIColor networkingColor]]; [self.scrollView addSubview:thirdView]; 

Además de cambiar la línea asignando el tamaño de contenido a:

 [self scrollView].contentSize = CGSizeMake(768 * 3, 1024); 

Esta vista no obtiene su marco establecido durante makeKeyAndVisible y está en el lugar correcto.

Para -makeKeyAndVisible el problema, recomiendo configurar la jerarquía de vista después de que la window tenga -makeKeyAndVisible llamado, posiblemente en una vistaWillAppear (no estoy seguro si eso tendrá el mismo problema) o estructurando su código para retrasar la distribución de La vista de desplazamiento. De forma alternativa, vuelva a configurar los cuadros más adelante como una anulación explícita de este error.

Espero que esto ayude a explicar lo que estaba sucediendo y que la evidencia que brinde sea clara y creíble; parece que ya tiene una solución para su caso particular, pero con suerte esta respuesta se presenta como una solución general para enmarcar la mala conducta cuando UIViewController tiene sus vistas dispuestas dentro de las vistas de desplazamiento.

¿Has intentado primero agregar las subvistas a la vista de desplazamiento y luego configurar su location? Encontré en una situación diferente que estaba tratando de agregar información a una vista antes de mostrarla en una vista de desplazamiento, solo para que los campos de text estén en blanco. Las vistas tienen una extraña peculiaridad en la que los valores pueden volver a su valor pnetworkingeterminado al mostrarse.

Sospecho que su problema es que sus dos vistas son demasiado grandes en sentido vertical para caber en el tamaño de contenido de su vista de desplazamiento. El contenido de su vista de desplazamiento es solo (768 * 2) x 900. Usted está evaluando que sus dos subprocesss son 768 x 1024. Como no caben de todos modos, la vista de desplazamiento probablemente solo nos da y los coloca a ambos en el origen. Cambia tu segunda línea a:

 [self scrollView].contentSize = CGSizeMake(768 * 2, 1024); 

Tomando un poco de código de esta publicación: UIScrollView agregando UIViewController como una vista secundaria? con UIPageControl , creo que lo solucioné usando self.scrollView.frame.size.width en lugar de usar un valor fijo de 768.

 [self scrollView].pagingEnabled = YES; [self scrollView].contentSize = CGSizeMake(self.scrollView.frame.size.width * 2, self.scrollView.frame.size.height); [[self scrollView] setDelegate:self]; CGRect frame1; frame1.origin.x = self.scrollView.frame.size.width * 0; frame1.origin.y = 0; frame1.size = self.scrollView.frame.size; // Model one oneView = [[OneViewController alloc] initWithNibName:@"OneViewController" bundle:nil]; [self.scrollView addSubview:oneView.view]; oneView.view.frame = frame1; // Model two CGRect frame2; frame2.origin.x = self.scrollView.frame.size.width * 1; frame2.origin.y = 0; frame2.size = self.scrollView.frame.size; twoView = [[TwoViewController alloc] initWithNibName:@"TwoViewController" bundle:nil]; [self.scrollView addSubview:twoView.view]; twoView.view.frame = frame2; 

Además, he actualizado mi repository para que pueda probar el proyecto como un todo. Aquí está el enlace de nuevo: http://bit.ly/PLe1Le 🙂