comment utiliser UIScrollView dans Interface Builder?


95

Bien que j'aie utilisé UIScrollViewavec succès dans le passé en le manipulant par programme, j'ai du mal à le faire fonctionner en le configurant exclusivement dans Interface Builder.

J'ai une simple page «À propos» dans mon application iPhone. Il a UITextViewquelques icônes et des liens vers mes autres applications. J'ai ajouté toutes ces vues à mon UIScrollView, en les organisant de sorte que leur taille totale soit> 480. Lorsque je lance mon application, la vue de défilement affiche uniquement le contenu qui tient sur l'écran, et rien ne défile.

Est-il possible de le faire entièrement via IB, ou dois-je manipuler le contentSize via du code?

Réponses:


130

Vous avez oublié de définir la propriété contentSize de UIScrollView. Curieusement, vous ne pouvez pas faire cela depuis Interface Builder. Vous devrez le faire à partir du contrôleur de vue gérant cette vue de défilement.


42
Wow, un peu rend IB plutôt inutile ... Cela a fait l'affaire, merci.
George Armhold

20
Vous pouvez créer une sous-classe de UIScrollvView qui vérifie s'il n'y a qu'une seule sous-vue à (0,0), puis définit automatiquement le contentSize en fonction de cette sous-vue.
Stefan Arentz

1
C'est le meilleur conseil que j'ai reçu depuis un moment. Je ne pouvais pas comprendre pourquoi ma vue de défilement ne fonctionnait pas et je n'ai trouvé cette information sur contentSize nulle part ailleurs. Merci.
Drew C le

46
J'essayais de comprendre comment définir contentSize dans Interface Builder et j'ai trouvé cette discussion. Au moins pour moi, dans Xcode 4.5, je peux le définir à l'aide des «Attributs d'exécution définis par l'utilisateur», en ajoutant une entrée nommée contentSizede type Sizeet en définissant la valeur souhaitée.
nlogax

5
Je suis toujours perplexe quant à la raison pour laquelle iOS ne définitcontentSize pas automatiquement la vue de défilement en fonction des dimensions de ses sous-vues , du moins en tant que comportement par défaut.
aroth

113

La réponse de Boby_Wan m'a fait réfléchir, et j'ai trouvé la solution suivante pour configurer le contentSize de UIScrollView à partir d'Interface Builder:

  1. Sélectionnez le UIScrollViewdans la scène Storyboard
  2. Accédez à l' inspecteur d'identité , créez un nouvel attribut d'exécution défini par l'utilisateur (cliquez sur le bouton +)
  3. Remplacez l'attribut Key Path parcontentSize
  4. Remplacez le type d' attribut parSize
  5. Maintenant , définissez la valeur à { largeur contenu souhaité , désiré la hauteur du contenu }

Par exemple, la définition de la valeur sur {320, 920} permettra à l'utilisateur de faire défiler tout un écran supplémentaire sur l'iPhone.

(J'utilise xcode 4.3.3, la cible de déploiement iOS du projet est 5.1)

Lorsque j'ai fait cela pour la première fois, j'ai reçu l'erreur suivante:

Configuration illégale:
     Attributs d'exécution définis par l'utilisateur de type taille avec des versions Xcode antérieures à 4.3
     MainStoryboard.storyboard

Si vous rencontrez également cette erreur, elle est simple à corriger: sélectionnez le Storyboard dans le navigateur de projet et affichez l' inspecteur de fichiers . Recherchez / développez la section Document Interface Builder , et il y a une liste déroulante pour le développement . Assurez-vous que ce paramètre est défini surXcode 4.3


7
Super trouvaille! PS: Je suis stupéfait que ce soit le mieux qu'Apple puisse faire. Je suppose que cela montre que même le personnel Apple n'utilise jamais son propre outil (constructeur d'interface) :).
Adam

Génial, cela vient de fonctionner pour moi dans Xcode 4.4. Mais maintenant, comment puis-je mettre des boutons sur la partie de la vue de défilement que je ne peux pas "voir" dans IB?
Robert Atkins

1
Je viens de le résoudre - vous devez relâcher le glissement lorsque le pointeur est toujours à l'intérieur de "l'écran", sinon il reviendra au moment où vous avez commencé. Quelle douleur.
Robert Atkins

J'ai essayé de cette façon, mais j'obtiens une erreur. "this class is not key value coding-compliant for the key keyPath"Pouvez-vous s'il vous plaît m'aider ce que je fais de mal? veuillez noter que j'utilise xamarin-ios-c #
SoftSan

25

Avec Autolayout (iOS6 +), vous pouvez éviter le paramétrage contentSize. Définissez plutôt les contraintes suivantes:

  1. Épinglez le haut de la vue de défilement en haut de son enfant le plus haut.
  2. Et épinglez le bas au bas de son enfant le plus bas.

1
Merci - le réglage contentSizene fonctionne pas avec Xcode 5 et iOS 7
Colincameron

18

Vous pouvez le faire en utilisant uniquement Interface Builder, accédez à l'inspecteur d'identité (le troisième onglet de l'inspecteur) et ajoutez un nouvel attribut d' exécution défini par l'utilisateur avec

  • Chemin de clé: contentSize
  • Type: Taille
  • Valeur: {width, height}

14

Il existe maintenant un moyen de faire un UIScrollViewparchemin sans quitter Storyboard :

  1. Sélectionnez le UIScrollViewdans le storyboard, accédez à l' inspecteur de taille et modifiez la valeur inférieure (ou toute autre valeur que vous devez modifier) ​​dans la section encarts de contenu à la hauteur de la zone de contenu.
  2. Accédez maintenant à l' inspecteur d'identité et créez un nouvel attribut d'exécution défini par l'utilisateur (en cliquant sur le bouton +) et nommez-le contentSize. Peu importe le type ou la valeur que vous remplissez (vous pouvez même laisser leur valeur par défaut).

Cela fera UIScrollViewfonctionner correctement, même si je ne sais pas pourquoi la deuxième étape est nécessaire (je l'ai découvert par hasard). :(


Changer la valeur inférieure en quoi?
zakdances

Modifiez-le à la hauteur de la zone de contenu. Il semble fonctionner et remplace la valeur que vous fournissez pour l'attribut "contentSize" défini par l'utilisateur.
Reid Ellis

Oui, Reid, vous avez raison: vous devez remplacer la valeur du bas par la hauteur de la zone de contenu. J'ai modifié mon message d'origine pour refléter cela. Je vous remercie!
RoberRM

4

une approche que j'ai utilisée dans le passé consiste à faire glisser la vue de défilement hors de sa vue contenant dans le générateur d'interface, et à définir sa taille réelle sur ce que doit être contentSize.

ce qui n'est pas intrinsèquement évident à propos du constructeur d'interface, c'est que vous pouvez avoir des vues non associées qui sont stockées dans la pointe, mais ne font pas partie de la vue principale à laquelle la pointe est principalement destinée.

dans la vue où vous voulez que la vue de défilement vive, placez un simple UIView, que vous utilisez comme espace réservé. (c'est simplement pour que vous puissiez concevoir visuellement son emplacement. Si vous n'utilisez que la vue entière, vous pouvez ignorer cette étape et utiliser le deuxième extrait de code que je fournis à la fin de cette réponse).

vous pouvez ensuite remplir la vue de défilement avec des commandes, en la présentant visuellement comme vous le souhaitez. donnez à la fois l'espace réservé et les propriétés scrollview dans votre contrôleur de vue afin d'y accéder au moment de l'exécution.

à l'exécution, dans - (void) viewDidLoad

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

alternativement (si vous n'avez pas utilisé d'espace réservé):

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

enfin, si vous «perdez» votre vue de défilement dans le constructeur d'interface (il est possible de la fermer pour qu'elle disparaisse de la grille de création), ne paniquez pas. cliquez simplement dessus dans la liste des objets à gauche de la grille de création.


1
Merci - cela a bien fonctionné. Vous devez également déclarer IBOutlets dans YourViewController.h pour l'espace réservé et les vues de défilement, et les connecter dans Interface Builder. Et enfin, dot.notation n'était pas apprécié par xCode pour la 3ème ligne, donc utilisé la syntaxe d'envoi de message normale - alors tout fonctionnait très bien!
jiy

pas de soucis. il y a toujours un danger lors de la publication d'extraits de code que certaines personnes ne puissent pas les utiliser pour obtenir le concept, plutôt que de s'attendre à ce que le code "exact" fonctionne dans toutes les situations.
non synchronisé

C'est la méthode que j'utilise réellement. Je n'ai même pas besoin de redimensionner ce programme du tout. Je pense que c'est ainsi que cela est prévu. C'est la seule vraie réponse.
user4951

Après l'avoir dessiné à l'extérieur, je vais simplement le déplacer en super vue. Tada.
user4951

En fait, j'ai commencé à utiliser la conception de vues en dehors d'une scène pour des blocs-notes et cela rend la vie beaucoup plus facile dans certaines situations, même sans rapport avec celle-ci. Merci pour cette réponse.
Benjamin

4

Dans Xcode 4.5 utilisant la mise en page automatique, je n'ai pas de section Insets de contenu dans mon inspecteur de taille. J'ai donc dû l'ajouter sous Attributs d'exécution définis par l'utilisateur, puis cela a bien fonctionné.

Ce que vous ajoutez dans "Attributs d'exécution définis par l'utilisateur" est keyPath == contentInset qui est de type "Rect" (UIEdgeInsets, qui a la même entrée qu'un Rect) et est défini comme {top, left}, {bottom, right}. Le contentSize définit uniquement la région de la fenêtre scrollview. contentInset définit la zone de défilement.

J'espère que cela aide quelqu'un dans la même situation.


Pour UITextView, utilisez "textContainerInset" keyPath
Dima Deplov

4

Bon nombre des réponses ci-dessus sont trompeuses ou dépassées. Depuis 2017 (peut-être beaucoup plus tôt), le constructeur d'interface prend en charge les vues de défilement avec un contenu automatiquement dimensionné. L'astuce est que XCode donne une signification spéciale et non standard aux contraintes entre le scrollview et le contenu qu'il contient. Ces contraintes «entrantes» n'affecteront pas réellement la taille du contenu comme vous pourriez autrement vous y attendre.

Cela signifie que vous pouvez par exemple avoir votre scrollview épinglé au bas de la vue principale avec une marge nulle, et également épingler le contenu de votre scrollview avec une marge zéro, mais le contenu ne sera pas réellement étiré par cela. Au lieu de cela, le contenu aura sa taille auto-déterminée (plus ci-dessous) et ce sera également la taille de la zone de défilement dans la vue de défilement.

Pensez-y comme ceci - Il y a une asymétrie dans la liaison des contraintes à une vue de défilement: Les contraintes de la vue de défilement vers le monde "extérieur" (parent) déterminent la taille et la position de la vue de défilement comme d'habitude. Mais les contraintes "à l'intérieur" du scrollview définissent en réalité la taille et la position de la zone scrollable du scrollview, en le liant au contenu.

Ceci n'est pas du tout évident car lorsque vous définissez les contraintes, XCode suggérera toujours l'espacement actuel et il se peut que vous n'ayez jamais pensé à changer intentionnellement les contraintes tournées vers l'intérieur et l'extérieur d'une manière qui soit en conflit. Mais vous pouvez et ils ont la signification décrite ci-dessus: l'un contrôle la disposition de la vue défilante et l'autre la taille de la zone de contenu défilable.

Je suis tombé par hasard sur cela par accident, puis voir comment cela semblait fonctionner m'a conduit à cet article qui l'explique complètement et cite la source de la documentation Apple pour cela:

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

Une dernière information critique, à propos de la taille auto-déterminée du contenu: vous pouvez avoir l'impression que vous êtes dans un catch-22 ici parce que vous dimensionnez normalement votre contenu par exemple à la largeur de la vue parent, mais dans ce cas, le parent est le scrollview et comme décrit ci-dessus - la contrainte n'affectera pas la taille de votre contenu. La réponse ici est de se rappeler que vous pouvez contraindre les éléments à des éléments qui ne sont pas directement voisins dans votre hiérarchie de vues: par exemple, vous pouvez définir la largeur de votre vue de contenu sur la largeur de la vue principale au lieu d'essayer en vain d'obtenir la vue de défilement pour le faire pour vous.


2

Si vous cliquez sur l'icône Propriétés de n'importe quel contrôleur de vue dans Interface Builder, vous pouvez le définir sur une taille «Forme libre» dans les mesures simulées et modifier la taille de la vue principale pour qu'elle corresponde à la taille de contenu souhaitée.

De cette façon, vous pouvez créer le contenu de votre ScrollView comme s'il s'agissait d'une grande vue. Comme il ne s'agit que d'une métrique simulée, votre contrôleur de vue sera redimensionné aux limites de la fenêtre lorsqu'il est chargé.


2

La configuration d'un UIScrollView via Interface Builder n'est pas intuitive. Voici ma liste de contrôle pour le configurer:

  1. Sélectionnez le fichier XIB de UIViewController. Dans "Identity Inspector" du générateur d'interface, changez UIView en type de classe UIScrollView

  2. Sous "Inspecteur de fichiers", décochez la case Mise en page automatique

  3. Sous "Inspecteur d'attributs", modifiez la taille en Forme libre. Vous pouvez ensuite étirer la vue de défilement manuellement ou vous pouvez spécifier une largeur et une hauteur personnalisées sous "Inspecteur de taille".

  4. Dans "Inspecteur d'identité", ajoutez un nouvel attribut d'exécution défini par l'utilisateur appelé "contentSize" de type "Size" et modifiez-le en une valeur telle que {320, 1000}. Vous ne pouvez plus définir cela par programme et avez donc besoin de cette étape pour que la vue défilement sache que le contenu de la vue défilement est plus grand que la fenêtre.


2

Supprimez simplement la mise en page automatique sur votre vue de défilement. alors le code est aussi simple que ceci:

scrollviewName.contentSize = CGSizeMake(0, 650);

créez simplement une propriété iboulet sur un fichier .h puis synthétisez sur un fichier .m. Assurez-vous que le défilement est activé.


1

Oui, st3fan a raison, la propriété contentSize de UIScrollView doit être définie. Mais vous ne devez pas désactiver la mise en page automatique à cette fin. Vous pouvez facilement configurer contentSize de UIScrollView avec mise en page automatique dans IB uniquement, sans aucun code.

Il est important de comprendre que lors de l'utilisation de la mise en page automatique contentSize de UIScrollView n'est pas défini directement, il est calculé en fonction des contraintes de toutes les sous-vues de UIScrollView. Et tout ce dont vous avez besoin est de fournir des contraintes appropriées pour les sous-vues dans les deux sens.

Par exemple, si vous n'avez qu'une seule sous-vue, vous pouvez définir sa hauteur et son espace de haut en bas pour superview (c'est-à-dire scrollView dans notre cas) contentSize.height est calculé comme somme

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

contentSize.width est calculé de manière similaire à partir des contraintes horizontales.

S'il y a trop peu de contraintes pour calculer correctement contentSize, un petit bouton rouge est affiché près de l'élément View Controller Scene pour informer sur l'ambiguïté de la disposition.

S'il y a beaucoup de sous-vues, il peut s'agir d'une "chaîne" de contraintes: de haut en haut de la sous-vue, des hauteurs et des espaces entre les sous-vues et du bas de la sous-vue vers le bas comme dans la réponse de Danyal Aytekin .

Mais en pratique, dans la plupart des cas, il est plus pratique d'ajouter simplement une vue vide avec la taille requise et de définir les espaces en haut, à gauche, en bas, à droite de scrollView sur 0. Vous pouvez utiliser cette vue comme "vue du contenu", c'est-à-dire mettre toutes les autres sous-vues dessus ou si vous avez déjà de nombreuses sous-vues et que vous ne voulez pas les déplacer et configurer à nouveau la mise en page, vous pouvez ajouter cette vue auxiliaire aux sous-vues existantes et la masquer.

Pour rendre scrollView scrollable, le contenu calculé doit être supérieur à la taille de scrollView.


1

Vous pouvez avoir UIScrollView dans StoryBoard avec des mises en page automatiques. En gros, ce dont vous avez besoin est:

  1. Ajouter UIScrollView
  2. Ajoutez-y toutes les contraintes (comme les inserts des bords supérieur, gauche, droit et inférieur)
  3. Ajouter un UIView 'conteneur' à UIScrollView
  4. Si vous voulez juste un défilement dans un sens (par exemple, vertical): définissez la hauteur explicitement (pour l'instance, 600) et la largeur du lien à la largeur de UIScrollView.
  5. Si vous voulez un défilement bidirectionnel, définissez simplement la largeur et la hauteur.

configuration du storyboard



0

Je trouve un moyen plus pratique.

1: Mettez à l'échelle la taille de la vue de défilement pour contenir toute l'interface utilisateur à l'intérieur.

2: Ajoutez un iboutlet de la vue de défilement.

3: Dans viewDidLoad, enregistrez le frame.size de la vue de défilement.
(par exemple _scrollSize = _scrollView.frame.size;)

4: Dans viewWillAppear, définissez le contentSize par le CGSize que vous avez enregistré auparavant.
(par exemple _scrollView.contentSize = _scrollSize;)

5: Terminé ~


0
  1. Ajouter UIViewController
  2. Dans UIViewController 'Attribute Inspector -> Simulated Metrics' set size Freeform
  3. Dans UIViewController 'Size Inspector -> View Controller' définir la hauteur 800
  4. Ajouter UIScrollView dans UIViewController
  5. Ajoutez toutes les contraintes à UIScrollView (haut, gauche, droite, bas) et ajoutez l'alignement X = centre
  6. Ajouter UIView dans UIScrollView
  7. Ajoutez toutes les contraintes à UIView (haut, gauche, droite, bas) et ajoutez l'alignement X = centre. Oui, comme pour UIScrollView dans # 3, mais pour UIView
  8. Ajoutez une contrainte de hauteur à UIView. Par exemple 780
  9. Courir

Storyboard


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.