¿Cómo uso UIScrollView en Interface Builder?

95

Si bien lo he usado con UIScrollViewéxito en el pasado manipulándolo mediante programación, tengo problemas para que funcione configurándolo exclusivamente en Interface Builder.

Tengo una página "acerca de" simple en mi aplicación para iPhone. Tiene UITextViewalgunos íconos y enlaces a mis otras aplicaciones. He agregado todas estas vistas a mi UIScrollView, organizándolas de modo que su tamaño total sea> 480. Cuando abro mi aplicación, la vista de desplazamiento muestra solo el contenido que cabe en la pantalla, y nada se desplaza.

¿Es posible hacer esto completamente a través de IB, o debo manipular contentSize a través del código?

George Armhold
fuente

Respuestas:

130

Olvidó establecer la propiedad contentSize de UIScrollView. Curiosamente, no puedes hacer esto desde Interface Builder. Deberá hacerlo desde el controlador de vista que gestiona esta vista de desplazamiento.

Stefan Arentz
fuente
42
Vaya, hace que IB sea bastante inútil ... Esto funcionó, gracias.
George Armhold
20
Puede crear una subclase de UIScrollvView que verifique si solo hay una subvista en (0,0) y luego establece automáticamente contentSize en función de esa subvista.
Stefan Arentz
1
Ese es el mejor consejo que he recibido en mucho tiempo. No pude entender por qué mi vista de desplazamiento no funcionaba y no encontré esa información sobre contentSize en ningún otro lugar. Gracias.
Drew C
46
Estaba tratando de averiguar cómo configurar contentSize en Interface Builder y encontré esta discusión. Al menos para mí, en Xcode 4.5, puedo configurarlo usando "Atributos de tiempo de ejecución definidos por el usuario", agregando una entrada con el nombre contentSizedel tipo Sizey configurando el valor deseado.
nlogax
5
Todavía estoy desconcertado con respecto a por qué iOS no solo configura automáticamente la vista contentSizede desplazamiento en función de las dimensiones de sus subvistas , al menos como el comportamiento predeterminado.
aroth
113

La respuesta de Boby_Wan me hizo pensar, y encontré la siguiente solución para configurar el contentSize de UIScrollView desde Interface Builder:

  1. Seleccione UIScrollViewen la escena del Storyboard
  2. Vaya al inspector de identidad , cree un nuevo atributo de tiempo de ejecución definido por el usuario (haga clic en el botón +)
  3. Cambie el atributo Ruta de la clave acontentSize
  4. Cambie el tipo de atributo aSize
  5. Ahora ajuste el valor de { contenido de ancho deseado , contenido deseado altura }

por ejemplo, establecer el valor en {320, 920} permitirá al usuario desplazarse hacia abajo en una pantalla adicional completa en el iPhone.

(Estoy usando xcode 4.3.3, el objetivo de implementación de iOS del proyecto es 5.1)

Cuando hice esto por primera vez, recibí el siguiente error:

Configuración ilegal:
     atributos de tiempo de ejecución definidos por el usuario de tipo de tamaño con versiones de Xcode anteriores a 4.3
     MainStoryboard.storyboard

Si usted también recibe este error, es fácil de solucionar: seleccione el Guión gráfico en el Navegador de proyectos y abra el inspector de archivos . Busque / expanda la sección Documento de Interface Builder , y hay un menú desplegable para Desarrollo . Asegúrese de que esté configurado enXcode 4.3

Herr Grumps
fuente
7
¡Increíble hallazgo! PD: Me sorprende que esto sea lo mejor que pueda hacer Apple. Supongo que esto muestra que incluso el personal de Apple nunca usa su propia herramienta (constructor de interfaces) :).
Adam
Genial, esto acaba de funcionarme en Xcode 4.4. Pero ahora, ¿cómo coloco botones en la parte de la vista de desplazamiento que no puedo "ver" en IB?
Robert Atkins
1
Lo acabo de resolver: tienes que soltar el arrastre cuando el puntero todavía está dentro de la "pantalla", de lo contrario, volverá a cuando empezaste. Que dolor.
Robert Atkins
Lo intenté de esa manera, pero aparece un error. ¿ "this class is not key value coding-compliant for the key keyPath"Pueden ayudarme, qué estoy haciendo mal? tenga en cuenta que uso xamarin-ios-c #
SoftSan
25

Con Autolayout (iOS6 +), puede evitar la configuración contentSize. En su lugar, establezca las siguientes restricciones:

  1. Fija la parte superior de la vista de desplazamiento a la parte superior de su elemento secundario superior.
  2. Y fije la parte inferior a la parte inferior de su hijo más inferior.
Danyal Aytekin
fuente
1
Gracias - la configuración contentSizeno funciona con Xcode 5 y iOS 7
colincameron
18

Puede hacerlo utilizando solo Interface Builder, vaya al Inspector de identidad (la tercera pestaña del inspector) y agregue un nuevo atributo de tiempo de ejecución definido por el usuario con

  • Ruta clave: contentSize
  • Tipo: tamaño
  • Valor: {ancho, alto}
Anton Banchev
fuente
14

Ahora hay una forma de hacer un UIScrollViewpergamino sin salir del Storyboard :

  1. Seleccione UIScrollViewen el Storyboard, vaya al inspector de tamaño y cambie el valor Inferior (o cualquier otro valor que necesite cambiar) en la sección Inserciones de contenido a la altura del área de contenido.
  2. Ahora vaya al inspector de identidad y cree un nuevo atributo de tiempo de ejecución definido por el usuario (haciendo clic en el botón +) y asígnele un nombre contentSize. No importa qué tipo o valor ingrese (incluso puede dejar su valor predeterminado).

Esto hará que el UIScrollViewtrabajo funcione correctamente, aunque no sé por qué es necesario el segundo paso (lo descubrí por casualidad). :(

RoberRM
fuente
¿Cambiar el valor Inferior a qué?
zakdances
Cámbielo a la altura del área de contenido. Parece funcionar y anula el valor que proporciona para el atributo "contentSize" definido por el usuario.
Reid Ellis
Sí, Reid, tienes razón: debes cambiar el valor Inferior a la altura del área de contenido. He editado mi publicación original para reflejar esto. ¡Gracias!
RoberRM
4

Un enfoque que he usado en el pasado es arrastrar la vista de desplazamiento fuera de la vista que la contiene en el generador de interfaces y establecer su tamaño real en lo que desea que sea contentSize.

Lo que no es inherentemente obvio sobre el generador de interfaces es que puede tener vistas no asociadas que se almacenan en la plumilla, pero que no forman parte de la vista principal para la que es principalmente la plumilla.

en la vista donde desea que viva la vista de desplazamiento, coloque una UIView simple, que usará como marcador de posición. (Esto es simplemente para que pueda diseñar visualmente su ubicación. Si solo está usando la vista completa, puede omitir este paso y usar el segundo fragmento de código que proporciono al final de esta respuesta).

A continuación, puede completar la vista de desplazamiento con controles, colocándola visualmente como desea que sea. proporcione tanto el marcador de posición como las propiedades de vista de desplazamiento dentro de su controlador de vista para que pueda acceder a ellos en tiempo de ejecución.

en tiempo de ejecución, en - (void) viewDidLoad

scrollView.contentSize = scrollView.frame.size;
scrollView.frame = placeholder.frame;
[placeholder.superview addSubView:scrollView];
[placeholder removeFromSuperview];

alternativamente (si no usó un marcador de posición):

CGRect f = self.view.frame;
scrollView.contentSize = f.size;
f.origin.x = 0;
f.origin.y = 0;
scrollView.frame = f;
[self.view addSubView:scrollView];

finalmente, si "pierde" su vista de desplazamiento en el generador de interfaces (es posible cerrarla para que desaparezca de la cuadrícula de diseño), no se asuste. simplemente haga clic en él en la lista de objetos a la izquierda de la cuadrícula de diseño.

desincronizado
fuente
1
Gracias, esto funcionó bien. También es necesario declarar IBOutlets en YourViewController.h para el marcador de posición y las vistas de desplazamiento, y conectarlos en Interface Builder. Y por último, xCode no apreció dot.notation para la tercera línea, así que usé la sintaxis de envío de mensajes normal, ¡entonces todo funcionó muy bien!
Jiy
sin preocupaciones. Al publicar fragmentos de código, siempre existe el peligro de que algunas personas no puedan usarlos para obtener el concepto, en lugar de esperar que el código "exacto" funcione en cada situación.
no sincronizado
Este es el método que realmente utilizo. Ni siquiera necesito cambiar el tamaño de este programa en absoluto. Creo que es la forma en que se pretende que se haga. Es la única respuesta verdadera.
user4951
Después de dibujarlo afuera, lo moveré a la vista superior. Tada.
user4951
De hecho, comencé a usar el diseño de algunas vistas fuera de una escena para scratchpads y eso hace la vida mucho más fácil en algunas situaciones, incluso no relacionadas con esta. Gracias por esta respuesta.
Benjamín
4

En Xcode 4.5 usando Autolayout, no tengo una sección de Inserciones de contenido en mi inspector de tamaño. Así que tuve que agregarlo en Atributos de tiempo de ejecución definidos por el usuario y luego funcionó bien.

Lo que agrega en "Atributos de tiempo de ejecución definidos por el usuario" es keyPath == contentInset que es de tipo "Rect" (UIEdgeInsets, que tiene la misma entrada que un Rect) y se define como {top, left}, {bottom, right}. ContentSize solo define la región de la ventana scrollview. contentInset define el área desplazable.

Espero que esto ayude a alguien en la misma situación.

Robert Wasmann
fuente
Para UITextView utilice "textContainerInset" keyPath
Dima Deplov
4

Muchas de las respuestas anteriores son engañosas o están desactualizadas. A partir de 2017 (posiblemente mucho antes) constructor de interfaces hace scrollviews de apoyo con contenido de tamaño automáticamente. El truco es que XCode da un significado especial y no estándar a las restricciones entre la vista de desplazamiento y el contenido dentro de ella. Estas restricciones "internas" en realidad no afectarán el tamaño del contenido como cabría esperar.

Esto significa que, por ejemplo, puede tener su vista de desplazamiento anclada en la parte inferior de la vista principal con margen cero, y también tener el contenido de su vista de desplazamiento anclada en la parte inferior de la vista de desplazamiento con margen cero, pero el contenido no se verá realmente estirado por esto. En cambio, el contenido obtendrá su tamaño autodeterminado (más abajo) y este también será el tamaño del área desplazable dentro de la vista de desplazamiento.

Piénselo así: hay una asimetría en las restricciones vinculantes a una vista de desplazamiento: las restricciones desde la vista de desplazamiento al mundo "exterior" (padre) determinan el tamaño y la posición de la vista de desplazamiento como de costumbre. Pero las restricciones "dentro" de la vista de desplazamiento en realidad establecen el tamaño y la posición del área de desplazamiento de la vista de desplazamiento, al vincularla al contenido.

Esto no es totalmente obvio porque cuando establece las restricciones, XCode siempre sugerirá el espaciado actual y es posible que nunca se le ocurra cambiar intencionalmente las restricciones que miran hacia adentro y hacia afuera de una manera que entre en conflicto. Pero puede y tienen el significado descrito anteriormente: uno controla el diseño de la vista de desplazamiento y otro controla el tamaño del área de contenido desplazable.

Me topé con esto por accidente y luego ver cómo parecía funcionar me llevó a este artículo que lo explica completamente y cita la fuente de documentos de Apple para esto:

https://spin.atomicobject.com/2014/03/05/uiscrollview-autolayout-ios/

Un último dato crítico, sobre el tamaño autodeterminado del contenido: puede sentir que está en una trampa porque normalmente dimensiona su contenido para, por ejemplo, el ancho de la vista principal, pero en este caso la vista principal es la vista de desplazamiento y como se describió anteriormente, la restricción no afectará el tamaño de su contenido. La respuesta aquí es recordar que puede restringir elementos a elementos que no sean directamente vecinos en su jerarquía de vista: por ejemplo, puede establecer el ancho de su vista de contenido al ancho de la vista principal en lugar de intentar en vano que la vista de desplazamiento lo haga para ti.

Pat Niemeyer
fuente
2

Si hace clic en el icono Propiedades de cualquier controlador de vista en Interface Builder, puede configurarlo en un tamaño de "Forma libre" en Métricas simuladas y cambiar el tamaño de la Vista principal para que sea el tamaño de contenido deseado.

De esta manera, puede crear el contenido de su ScrollView como si fuera una vista grande. Como es solo una métrica simulada, su controlador de vista cambiará de tamaño a los límites de la ventana cuando se cargue.

oliland
fuente
2

Configurar un UIScrollView a través de Interface Builder no es intuitivo. Aquí está mi lista de verificación para configurarlo:

  1. Seleccione el archivo XIB de UIViewController. En el "Inspector de identidad" del constructor de interfaces, cambie UIView al tipo de clase UIScrollView

  2. En "Inspector de archivos", desmarque Diseño automático

  3. En "Inspector de atributos", cambie el tamaño a Forma libre. A continuación, puede estirar la vista de desplazamiento manualmente o puede especificar un ancho y una altura personalizados en "Inspector de tamaño".

  4. En "Identity Inspector", agregue un nuevo atributo de tiempo de ejecución definido por el usuario llamado "contentSize" de tipo "Size" y cámbielo a un valor como {320, 1000}. Ya no puede configurar esto mediante programación y, por lo tanto, necesita este paso para que la Vista de desplazamiento sepa que el contenido de la Vista de desplazamiento es más grande que la ventana.

Masón libre
fuente
2

Simplemente elimine el diseño automático en su vista de desplazamiento. entonces el código es tan simple como esto:

scrollviewName.contentSize = CGSizeMake(0, 650);

simplemente cree una propiedad iboulet en el archivo .h y luego sintetice en el archivo .m. Asegúrese de que el desplazamiento esté habilitado.

Aldrin Equila
fuente
1

Sí, st3fan tiene razón, se debe establecer la propiedad contentSize de UIScrollView. Pero no debe desactivar el diseño automático para este propósito. Puede configurar fácilmente contentSize de UIScrollView con diseño automático solo en IB, sin ningún código.

Es importante comprender que cuando no se configura directamente contentSize de UIScrollView, se calcula en función de las restricciones de todas las subvistas de UIScrollView. Y todo lo que necesita es proporcionar las restricciones adecuadas para las subvistas en ambas direcciones.

Por ejemplo, si solo tiene una subvista, puede establecer su altura y espacio desde la parte superior e inferior a la supervista (es decir, scrollView en nuestro caso) contentSize.height se calcula como suma

Vertical Space (aSubview.top to Superview.top) + aSubview.height + Vertical Space (aSubview.top to Superview.top)

contentSize.width se calcula de manera similar a partir de restricciones horizontales.

Si hay muy pocas restricciones para calcular el tamaño del contenido correctamente, se muestra un pequeño botón rojo cerca del elemento Ver escena del controlador para informar sobre la ambigüedad del diseño.

Si hay muchas subvistas, puede ser una "cadena" de restricciones: subvista de arriba a arriba, alturas y espacios entre las subvistas y subvista de abajo a abajo como en la respuesta de Danyal Aytekin .

Pero en la práctica, en la mayoría de los casos, es más conveniente agregar una vista vacía con el tamaño requerido y establecer los espacios en la parte superior, izquierda, inferior, derecha de scrollView en 0. Puede usar esta vista como "Vista de contenido", es decir, poner todas las demás subvistas. en él o si ya tiene muchas subvistas y no desea moverlas y configurar el diseño nuevamente, puede agregar esta vista auxiliar a las subvistas existentes y ocultarla.

Para que scrollView, el contenido calculado desplazable, el tamaño debe ser mayor que el tamaño de scrollView.

Vladimir
fuente
1

Puede tener UIScrollView en StoryBoard con Autolayouts. Básicamente, lo que necesitas es:

  1. Agregar UIScrollView
  2. Agregue todas las restricciones (como inserciones desde los bordes superior, izquierdo, derecho e inferior)
  3. Agregar un UIView 'contenedor' a UIScrollView
  4. Si solo desea un desplazamiento en una dirección (por ejemplo, vertical): establezca la altura explícitamente (por ejemplo, 600) y enlace el ancho al ancho de UIScrollView.
  5. Si desea un desplazamiento bidireccional, simplemente configure el ancho y el alto.

configuración del guión gráfico

Eugene Braginets
fuente
0

Aquí hay una solución para diseñar ScrollView con un contenido más grande que la pantalla completamente en Storyboard (bueno, casi en su totalidad, también necesitará agregar 1 línea de código)

https://stackoverflow.com/a/19476991/1869369

Ronny Webers
fuente
0

Encuentro una forma más conveniente.

1: escala el tamaño de la vista de desplazamiento para que contenga toda la interfaz de usuario en su interior.

2: agregue un iboutlet de la vista de desplazamiento.

3: En viewDidLoad, guarde el tamaño del marco de la vista de desplazamiento.
(por ejemplo, _scrollSize = _scrollView.frame.size;)

4: En viewWillAppear, establezca contentSize por el CGSize que guardó antes.
(por ejemplo, _scrollView.contentSize = _scrollSize;)

5: Listo ~

Agas
fuente
0
  1. Agregar UIViewController
  2. En UIViewController 'Attribute Inspector -> Simulated Metrics' set size Freeform
  3. En UIViewController 'Size Inspector -> View Controller' establezca la altura 800
  4. Agregar UIScrollView en UIViewController
  5. Agregue todas las restricciones a UIScrollView (arriba, izquierda, derecha, abajo) y agregue alineación X = centro
  6. Agregar UIView en UIScrollView
  7. Agregue todas las restricciones a UIView (arriba, izquierda, derecha, abajo) y agregue alineación X = centro. Sí, lo mismo que para UIScrollView en el n. ° 3, pero para UIView
  8. Agregue restricción de altura a UIView. Por ejemplo 780
  9. correr

Storyboard

Alejandro
fuente
0

Crea un nuevo proyecto de Xcode

Navegue al archivo Main.storyboard

Seleccione ScrollView de la biblioteca de objetos.

Establecer marco para ScrollView.

Agregue otra vista para desplazarse por la vista y mantenga el marco igual que el de ScrollView.

Ahora, para establecer su altura y ancho dinámicamente, puede configurar A UIScrollView usando el diseño automático en XIB

Dilraj Singh
fuente