iOS Autolayout con UIScrollview: ¿Por qué la vista de contenido de la vista de desplazamiento no llena la vista de desplazamiento?

El siguiente código (llamado en viewDidLoad) da como resultado una pantalla totalmente roja. Espero que sea una pantalla completamente verde. ¿Por qué es rojo? ¿Y cómo puedo hacerlo todo verde?

UIScrollView* scrollView = [UIScrollView new]; scrollView.translatesAutoresizingMaskIntoConstraints = NO; scrollView.backgroundColor = [UIColor networkingColor]; [self.view addSubview:scrollView]; UIView* contentView = [UIView new]; contentView.translatesAutoresizingMaskIntoConstraints = NO; contentView.backgroundColor = [UIColor greenColor]; [scrollView addSubview:contentView]; NSDictionary* viewDict = NSDictionaryOfVariableBindings(scrollView,contentView); [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:0 views:viewDict]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics:0 views:viewDict]]; [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:0 views:viewDict]]; [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics:0 views:viewDict]]; 

Solutions Collecting From Web of "iOS Autolayout con UIScrollview: ¿Por qué la vista de contenido de la vista de desplazamiento no llena la vista de desplazamiento?"

Las restricciones con vistas de desplazamiento funcionan de manera ligeramente diferente a como lo hacen con otras vistas. Las restricciones entre contentView y su superview (el scrollView ) son para el contentSize scrollView , no para su frame . Esto puede parecer confuso, pero en realidad es bastante útil, lo que significa que nunca tendrá que ajustar contentSize , sino que contentSize se ajustará automáticamente para adaptarse a su contenido. Este comportamiento se describe en la Nota técnica TN2154 .

Si desea definir el tamaño del contenido de la pantalla en la pantalla o algo así, tendría que agregar una restricción entre la contentView y la vista principal, por ejemplo. Es cierto, ciertamente, antitético de poner contenido en el scrollview, así que probablemente no lo aconsejaría, pero se puede hacer.


Para ilustrar este concepto, que el tamaño de contentView será impulsado por su contenido, no por los bounds de scrollView , agregue una label a su contentView :

 UIScrollView* scrollView = [UIScrollView new]; scrollView.translatesAutoresizingMaskIntoConstraints = NO; scrollView.backgroundColor = [UIColor networkingColor]; [self.view addSubview:scrollView]; UIView* contentView = [UIView new]; contentView.translatesAutoresizingMaskIntoConstraints = NO; contentView.backgroundColor = [UIColor greenColor]; [scrollView addSubview:contentView]; UILabel *randomLabel = [[UILabel alloc] init]; randomLabel.text = @"this is a test"; randomLabel.translatesAutoresizingMaskIntoConstraints = NO; randomLabel.backgroundColor = [UIColor clearColor]; [contentView addSubview:randomLabel]; NSDictionary* viewDict = NSDictionaryOfVariableBindings(scrollView, contentView, randomLabel); [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:0 views:viewDict]]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics:0 views:viewDict]]; [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:0 views:viewDict]]; [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics:0 views:viewDict]]; [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[randomLabel]-|" options:0 metrics:0 views:viewDict]]; [contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[randomLabel]-|" options:0 metrics:0 views:viewDict]]; 

Ahora verá que contentView (y, por lo tanto, scrollView de scrollView ) está ajustado para ajustarse a la label con márgenes estándar. Y debido a que no especificé el ancho / alto de la label, eso se ajustará según el text que coloque en esa label.


Si desea que el contentView la contentView también se ajuste al ancho de la vista principal, podría networkingefinir su punto de viewDict como tal, y luego agregar estas restricciones adicionales (además de todas las demás, anteriores):

 UIView *mainView = self.view; NSDictionary* viewDict = NSDictionaryOfVariableBindings(scrollView, contentView, randomLabel, mainView); [mainView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[contentView(==mainView)]" options:0 metrics:0 views:viewDict]]; 

Hay un problema conocido (error?) Con tags de varias líneas en scrollviews, que si quieres cambiar el tamaño según la cantidad de text, tienes que hacer algún juego de manos, como por ejemplo:

 dispatch_async(dispatch_get_main_queue(), ^{ randomLabel.prefernetworkingMaxLayoutWidth = self.view.bounds.size.width; }); 

Intenté que la respuesta de Rob se vea bien al principio. ¡PERO! si también habilitas el zoom , este código de Autolayout se interpondrá en el path. Continúa cambiando el tamaño de la vista de contenido cuando se acerca el zoom. Es decir, si aumenté el zoom (zoomScale> 1), no podré desplazar las partes fuera de la pantalla.

Después de días de luchar con Autolayout, lamentablemente no pude encontrar ninguna solución. Al final, ni siquiera importa (wat? Ok, lo siento). Al final, simplemente elimino Autolayout en contentView (uso un tamaño de contenido contentView), y luego en layoutSubviews, ajuste el self.scrollView.contentInset . (Estoy usando Xcode5, iOS 7)

Sé que esta no es una solución directa a esta pregunta. Pero solo quiero señalar una solución fácil. ¡Funciona perfectamente para centrar una ContentView de tamaño fijo en un scrollView, con solo 2 líneas de código! Espero que pueda ayudar a alguien;)

 - (void)layoutSubviews { [super layoutSubviews]; // move contentView to center of scrollView by changing contentInset, // because I CANNOT set this with AUTOLAYOUT!!! CGFloat topInset = (self.frame.size.height - self.contentView.frame.size.height)/2; self.scrollView.contentInset = UIEdgeInsetsMake(topInset, 0, 0, 0); }