Ambigüedad del tamaño del contenido desplazable de UIScrollView
Compañeros desarrolladores, tengo problemas con AutoLayout en Interface Builder (Xcode 5/iOS 7). Es muy básico e importante, así que creo que todos deberían saber cómo funciona correctamente. Si esto es un error en Xcode, ¡es crítico!
Entonces, cada vez que tengo una jerarquía de vistas como esta, tengo problemas:
>UIViewController
>> UIView
>>>UIScrollView
>>>>UILabel (or any other comparable UIKit Element)
UIScrollView tiene restricciones sólidas, por ejemplo, 50 px de cada lado (no hay problema). Luego agrego una restricción de espacio superior a UILabel (no hay problema) (e incluso puedo fijar la altura/ancho de la etiqueta, no cambia nada, pero debería ser innecesario debido al tamaño intrínseco de la etiqueta)
El problema comienza cuando agrego una restricción final a UILabel:
Por ejemplo, espacio final para: Supervisión es igual a: 25
Ahora aparecen dos advertencias y no entiendo por qué:
A) Ambigüedad en el tamaño del contenido desplazable (la vista de desplazamiento tiene un alto/ancho de contenido desplazable ambiguo)
B) Vistas fuera de lugar (Etiqueta esperada: x= -67 Real: x= 207
Hice este ejemplo mínimo en un proyecto nuevo que puedes descargar y adjunté una captura de pantalla. Como puede ver, Interface Builder espera que la etiqueta se encuentre fuera del límite de UIScrollView (el rectángulo discontinuo naranja). Actualizar el marco de la etiqueta con la herramienta Resolver problemas la mueve allí mismo.
Tenga en cuenta: si reemplaza UIScrollView con UIView, el comportamiento es el esperado (el marco de la etiqueta es correcto y de acuerdo con la restricción). Parece que hay un problema con UIScrollView o me estoy perdiendo algo importante.
Cuando ejecuto la aplicación sin actualizar el marco de la etiqueta como lo sugiere IB, se coloca bien, exactamente donde se supone que debe estar y UIScrollView se puede desplazar. Si actualizo el marco, la etiqueta no está a la vista y UIScrollView no se desplaza.
¡Ayúdame Obi-Wan Kenobi! ¿Por qué el diseño ambiguo? ¿Por qué esa visión fuera de lugar?
Puede descargar el proyecto de muestra aquí e intentar descubrir qué está pasando: https://github.com/Wirsing84/AutoLayoutProblem
Actualizado
Hoy en día, Apple se dio cuenta del problema que resolvimos hace muchos años (lol_face) y proporciona una Guía de diseño de contenido y una Guía de diseño de marcos como parte del UIScrollView
. Por lo tanto, debe seguir los siguientes pasos:
Igual que la respuesta original a continuación;
Para esto
contentView
, establezca los márgenes superior, inferior, izquierdo y derecho en 0 y fijelos en la Guía de diseño de contenido de la vista de desplazamiento;Ahora establezca la
contentView
altura de igual a la altura de la Guía de diseño del marco . Haz lo mismo con el ancho;Finalmente, establezca la prioridad de las restricciones de igual altura en 250 (si necesita que la vista se desplace verticalmente, el ancho se desplace horizontalmente).
Finalizado .
Ahora puede agregar todas sus vistas en ese archivo contentView
y el contentSize
tamaño del archivo scrollView
cambiará automáticamente de acuerdo con el archivo contentView
.
No olvide establecer la restricción desde la parte inferior del último objeto contentView
hasta el contentView
margen.
Original [obsoleto]
Entonces lo resolví de esta manera:Dentro del
UIScrollView
add aUIView
(podemos llamarlocontentView
);En esto
contentView
, establezca los márgenes superior, inferior, izquierdo y derecho en 0 (por supuesto, descrollView
cuál es elsuperView
); Configure también alinear el centro horizontal y verticalmente ;
Xcode 11+
La forma más sencilla usando autolayout
:
- Agréguelo
UIScrollView
y fíjelo0,0,0,0
a la supervisión (o al tamaño que desee) - Agregue un contenedor de
UIView
tipo dentro de ScrollView, fíjelo0,0,0,0
a los 4 lados y céntrelohorizontally
yvertically
. - En el inspector de tamaño del contenedor, cambie
bottom
yalign center Y
priorice a 250. (para cambio de desplazamiento horizontaltrailing
yalign center X
) - Agregue todas las vistas que necesite en dicho contenedor (UIView). No olvide establecer la restricción inferior en la vista más baja.
- Seleccione
UIScrollView
, seleccione el inspector de tamaño y anule la selecciónContent Layout Guides
.
Xcode 11+, Rápido 5
Si se pregunta por qué todas las respuestas ya no funcionan, asegúrese de haber fijado la vista de contenido (la que colocó dentro de la vista de desplazamiento) en la Guía de diseño de contenido de la vista de desplazamiento y NO en la Guía de diseño de marco.
Los bordes de la vista de contenido (inicial, final, superior, inferior) no deben fijarse como los iniciales de la imagen - a la Guía de diseño de marcos
pero así: a la Guía de diseño de contenido.
Y entonces la mayoría de las respuestas funcionarán para usted.
El enfoque más simple ahora es el siguiente:
- Poner la vista de desplazamiento en la vista raíz
- Anclar todos los lados de la vista de desplazamiento a la supervista
- Tome otra UIView (la llamaremos vista de contenido) y colóquela dentro de la vista de desplazamiento
- Fije todos los lados de la vista de contenido para desplazarse por la Guía de diseño de contenido de la vista
- Fije el ancho de la vista de contenido para que sea igual a la Guía de diseño de marcos de la vista de desplazamiento
- Corrija la altura de la vista de contenido de la forma que desee (en el siguiente ejemplo utilicé solo una restricción de altura constante)
En general, su estructura en la implementación más simple se verá así
Me tomó un tiempo localizar este error; inicialmente intenté fijar el tamaño de ScrollView pero el mensaje de error dice claramente "tamaño del contenido". Me aseguré de que todo lo que fijé desde la parte superior de ScrollView también estuviera fijado en la parte inferior. De esa manera, ScrollView puede calcular la altura de su contenido encontrando la altura de todos los objetos y restricciones. Esto resolvió la altura ambigua del contenido, el ancho es bastante similar... Inicialmente tenía la mayoría de las cosas X centradas en ScrollView, pero también tenía que fijar los objetos al costado de ScrollView. No me gusta esto porque el iPhone6 puede tener una pantalla más ancha pero eliminará el error de "ancho de contenido ambiguo".
Debe crear una UIView
subvista como UIScrollView
se describe a continuación:
UIViewController
UIView
'Vista principal'UIScrollView
UIView
'Vista de contenedor'- [Tu contenido]
El segundo paso es hacer las UIScrollView
restricciones. Hice esto con las restricciones superior, inferior, inicial y final de su superView.
Luego agregué las restricciones para el contenedor de UIScrollView
y aquí es donde comienza el problema. Cuando pones las mismas restricciones (superior, inferior, inicial y final), el Storyboard muestra un mensaje de advertencia:
"Tiene un ancho de contenido desplazable ambiguo" y "Tiene un alto de contenido desplazable ambiguo"
Continue with the same constraints above, and just add the constraints Equal Height
and Equal Width
to your Container View in relation to the Main View and not to your UIScrollView
. In other words the Container View's constraints are tied to the UIScrollView
's superview.
After that you will not have warnings in your Storyboard and you can continue adding the constraints for your subviews.