Trabajar con la guía de layout superior en UIScrollView a través de layout automático

Quiero usar la Top Layout Guide en UIScrollView través del layout automático. Sin el layout automático UIScrollView funciona bien con la Top Layout Guide . introduzca la descripción de la imagen aquí

Pero cuando incruste el UIButton en UIScrollView , no lo hace. introduzca la descripción de la imagen aquí

Sé que es porque UIScrollView no es el mismo nivel de jerarquía con la Top Layout Guide . Pero creo que puede haber una buena solución para resolver este problema.

Tienes razón en estar confundido. Es un poco contradictorio, pero las guías de layout superior e inferior son irrelevantes para configurar un UIScrollView de modo que su contenido desplazable se superponga a la barra de navigation translúcida, que es el efecto que está tratando de lograr.

qué hacer

Dada la jerarquía de vista que ha mostrado en la segunda image, esto es lo que debe hacer en iOS8:

  1. Configure el controller de vista para que "Extender bordes debajo de la barra superior" esté marcado (en el código, use edgesForExtendedLayout ). Esto asegurará que el controller de vista exponga su vista raíz para que se solape con la barra de navigation.

  2. Configure las restricciones de vista de desplazamiento para que el borde superior de la vista de desplazamiento tenga un desplazamiento cero desde el borde superior de su vista de supervisión, no el espacio cero desde la guía de layout superior. Esto asegurará que la vista de colección llena la vista raíz y, por lo tanto, también se solapa con la barra de navigation, que es necesaria para que el contenido de la vista de desplazamiento pueda desplazarse debajo de la barra de navigation. (IB podría pelear contigo por esto. Mira la nota al pie abajo.)

  3. Entonces, ¿cómo asegurarse de que la vista de desplazamiento tenga alguna idea de dónde está la barra de navigation, de modo que (por ejemplo) no siempre ubique su contenido debajo de la barra de navigation? La respuesta no tiene nada que ver con las guías de layout. En el controller de vista, marque la casilla "Ajusta las inserciones de la vista de desplazamiento" (o en el código, ajusta automáticamente las inserciones de vista de desplazamiento). Esto hará que el controller de vista ajuste automáticamente la propiedad contentInset la vista de contentInset para que la vista de desplazamiento posicione su contenido adecuadamente.

Esto funcionara

que esta pasando

Entonces, ¿por qué es esta la respuesta? ¿Y por qué es tan confuso?

Francamente, es fácil confundirse porque las guías de layout superior e inferior se nos presentan de forma destacada como elementos que transmiten información de layout sobre elementos superpuestos traslúcidos. Sin embargo, no son el único mecanismo de layout "translúcido". Son directamente relevantes solo para el posicionamiento de subvistas "normales", es decir, no para la vista raíz del controller de vista y no para el contenido dentro de un UIScrollView.

El contenido dentro de una vista de desplazamiento (o una subclass como UICollectionView y UITableView) siempre se ubicará de una manera más complicada que involucre el desplazamiento de la vista en sí, afectada por properties como contentInset , contentOffset , etc. (Realmente, si el layout de la vista de desplazamiento fuera un cosa fácil, ¿por qué Apple habría dedicado sesiones WWDC para desplazarse por el layout de la vista durante los últimos cuatro años ?!

Para resumir, como indican los pasos anteriores, los tres mecanismos distintos de conocimiento de translucidez para gestionar el layout son los siguientes:

  1. Extends Edges determina si el controller de vista posiciona su vista de raíz para que se solape con la barra de navigation.

  2. Las guías de layout proporcionan una métrica que indica dónde está el área de contenido "principal", teniendo en count las barras traslúcidas. Puede usarlos con el layout automático para colocar las vistas normales para que no se superpongan. O puede acceder a los valores numéricos en el código.

  3. Las Inserciones de vista de desplazamiento son la forma correcta de garantizar que el contenido de una vista de desplazamiento pueda superponerse pero que no siempre se superponga. La propiedad automaticallyAdjustsScrollViewInsets en el controller de vista puede hacer esto por usted automáticamente en casos simples. (Presumiblemente, esta propiedad solo hace que el controller de vista actualice el contenido de la vista de contentInset basado en los mismos valores que expone a través de las guías de layout. Por lo tanto, si necesita administrar las inserciones usted mismo, así lo haría).

combatiendo la manía de la guía de layout de IB

Una nota de pie de página sobre "Peleas con IB":

Desafortunadamente, Interface Builder podría pelearte cuando trates de restringir el borde de la vista de desplazamiento al borde de la supervisión. Si presiona Ctrl y arrastra desde la vista de desplazamiento a la vista de supervisión, cuando aparezca el menu de posibles restricciones para agregar entre esas vistas, podría intentar limitar la vista de desplazamiento contra las guías de layout del controller de vista. Esto se debe a que IB, sin sentido, prefiere las guías de layout a los bordes de la vista de supervisión, cuando la vista de supervisión es la vista de raíz. Pero cuando estás trabajando con una vista de desplazamiento, esto es lo incorrecto .

¿Por qué? Por ejemplo, suponga que acepta una restricción contra la guía de layout. Luego, terminarás con una restricción superior en tu scrollview que lo limita a topLayoutGuide-64.0. Eso -64.0 es un valor de código fijo que compensa la altura exacta de una barra de navigation. Entonces, ¿qué sucede cuando un buen día la barra de navigation no es igual a 64pt? ¿O cuando simplemente desactivas la barra de navigation por completo? ¿O quieres reutilizar esta escena en un context sin una barra de navigation? Respuesta: entonces obtienes un layout roto.

Entonces, ¿cómo obligas a IB a agregar una restricción desde la vista de desplazamiento al borde de la supervisión, en oposition a la guía de layout? Por lo que puedo decir, la respuesta es que no puedes agregar esa restricción correctamente en IB haciendo un ctrl-drag entre vistas.

En su lugar, debe seleccionar la vista y luego usar el control "Pin" en la parte inferior del canvas. Este es el que parece una H mayúscula con una caja en su centro. En la sección superior del dialog emergente Pin, en la sección con el pequeño diagtwig que muestra las restricciones de espacio de supervisión, puede usar los controles desplegables al lado de los campos de text para configurar si la restricción de espacio vincula una guía de layout o una supervisión. Esto se muestra a continuación:

Cuadro de diálogo Pin, para restringir guías de diseño vs vista

Enlace Github a proyectos de demostración: https://github.com/algal/ScrollViewUnderlapDemo

Mientras que la respuesta de algal parece haber funcionado antes de iOS 9.0, es innecesariamente complicada y rota más allá de iOS 9.0. La manera más fácil que también funciona más allá de iOS 9.0 y no requiere interacción con el layout automático es simplemente hacer lo siguiente:

  1. Asegúrese de Adjust Scroll View Insets están marcadas para el ViewController en Interface Builder (o configuran automaticallyAdjustsScrollViewInsets Adjust Scroll View Insets en true progtwigción).
  2. Establezca la class de la View raíz del ViewController en UIScrollView en Interface Builder (o reemplácelo manualmente (self.view) con un UIScrollView en código).

Al agregar restricciones de espacio, Xcode no muestra elementos que tengan una distancia negativa con su vista. Parece que agregó una restricción de espacio vertical entre UIScrollView y UIView . Elimine esa restricción, mueva su vista de desplazamiento a la Top Layout Guide y agregue una nueva restricción de espacio vertical entre UIScrollView y la Top Layout Guide .