Comment puis-je utiliser Autolayout pour définir des contraintes sur mon UIScrollview?

176

J'ai passé deux jours à essayer les différentes solutions pour les approches de mise en page automatique mixte et pure pour réaliser ce qui était une configuration triviale de scrollview avant la mise en page automatique, et c'est maintenant officiel - je dois être trop stupide. Je mets cela en place principalement dans Storyboard (enfin, c'est juste comme ça).

Alors, voici mon appel à l'aide.

Viewtree:

UIView
-UIView
-UIView
..-UIScrollview
...-UIButton
...-UIButton
...-UIButton

Les boutons sont censés défiler horizontalement (de gauche à droite et vice versa). Quelqu'un peut-il s'il vous plaît me faire savoir comment définir les contraintes pour y parvenir en utilisant pure Autolayout ???

-

J'ai essayé l'approche mixte, comme ceci:

UIView
- UIView
- UIView
..-UIScrollview
...-UIView (contentview)
....-UIButton
....-UIButton
....-UIButton

... et définir des contraintes de largeur et de hauteur fixes pour le contentviewet les translatesAutoresizingMaskIntoConstraintsparamètres conformément à la note technique d'Apple. Les boutons et la vue de défilement sont configurés à l'aide de contraintes. Cela fait défiler la vue de défilement (yay) mais hélas, ça défile trop loin! Pour autant que je sache, la largeur du défilement est en quelque sorte doublée par rapport à ce que j'ai défini pour la vue de contenu ??? !!! ???

J'ai également essayé l'approche de mise en page automatique pure, avec contentviewet sans. Toutes les vues sont translatesAutoresizingMaskIntoConstraints=NO, sauf pour self.view. Les boutons ont des contraintes de largeur / hauteur fixes et sont épinglés aux quatre bords de la vue de défilement. Rien ne défile.

Je suis donc totalement perplexe de savoir pourquoi je ne peux pas le faire fonctionner correctement. Toute aide est très appréciée, et si vous avez besoin d'autres informations, veuillez demander!

Capture d'écran MISE À JOUR avec solution - contraintes buttonZ:

entrez la description de l'image ici

EDIT @ Jamie Forrest La solution s'avère donc être la mauvaise contrainte de fin sur le dernier bouton. Au lieu de 6441, la valeur que j'avais définie était négative, -6441. Le problème est que lors de la définition de la valeur dans le storyboard, il existe deux options dans la barre d'outils Épingler:

entrez la description de l'image ici

La valeur actuelle du canevas est négative (conduisant à aucun défilement) et l'option ci-dessous est positive (activation du défilement). Cela signifie que je ne suis pas stupide mais au moins à moitié aveugle je suppose. Cependant, pour ma défense, n'est-il pas quelque peu dérangeant que XCode n'affiche pas d'erreur pour le paramètre «incorrect»?

MODIFIE DE NOUVEAU Maintenant c'est drôle ... changer la valeur de fin de -6441 (pas de défilement) à 6441 défilement activé. Mais mon vieil ami le "too much contentsize" était de retour, conduisant à une taille de contenu deux fois plus grande que ce qu'elle devrait être! La solution pour obtenir le défilement de contenu correct était de définir la contrainte de fin sur ZERO! Ce n'est pas évident lorsque vous travaillez dans Storyboard, mais en regardant le code de @Infinity James, c'est ce qu'il devrait être.

user1459524
la source
Où calculez-vous / définissez-vous la taille du contenu pour votre vue de défilement? En référence à votre première tentative en utilisant un contentView et vous avez dit qu'il défile trop loin.
Tim du
2
Autant que je sache, vous ne pouvez pas définir le contentSized'une UIScrollViewmise en page automatique uniquement. Et c'est le contentSizequi définit combien vous pouvez faire défiler. Vous devrez donc éventuellement définir cela manuellement quelque part. Pour le reste, vous pouvez utiliser des contraintes de mise en page pour configurer les cadres de vue les uns par rapport aux autres.
Guillaume
@Jeff, la taille du contenu est fixe, elle ne change jamais. J'ai défini la taille du contenu dans le storyboard en entrant manuellement la hauteur et la largeur correctes pour la vue du contenu, et j'épingle la hauteur et la largeur avec des contraintes dans le storyboard.
user1459524
Imprimez votre contentSize au moment de l'exécution, voyez s'il correspond aux valeurs que vous avez saisies. Le contentSize détermine la quantité de défilement, donc le problème avec votre première tentative est lié à contentSize.
Tim
@Guillaume, donc l'approche "pure autolayout" n'est pas si pure après tout? Mais comment définir le contentSize manuellement? Comme je l'ai mentionné ci-dessus, je règle la hauteur / largeur de la vue du contenu à des valeurs fixes (dans le storyboard). Mais il défile trop loin (2x).
user1459524

Réponses:

68

Il est difficile de voir les valeurs exactes et la configuration de vos contraintes lorsque vous les avez collées ici, donc je ne suis pas sûr de regarder vos captures d'écran où vous vous êtes trompé.

Au lieu d'expliquer ce qui ne va pas dans votre configuration, j'ai créé un exemple de projet de base avec une hiérarchie de vues et une configuration de contraintes très similaires à celles que vous décrivez. Le défilement horizontal fonctionne comme prévu dans l'exemple de projet, qui utilise l'approche «Pure AutoLayout» décrite par Apple dans la note technique .

J'ai également eu beaucoup de mal à faire fonctionner la mise en page automatique UIScrollView. La clé pour le faire fonctionner est de s'assurer que tous les éléments de la vue de défilement, pris ensemble, ont des contraintes qui finissent par se lier à tous les côtés de la vue de défilement et qui contribuent à ce que le système de mise en page automatique puisse déterminer une taille de contenu pour le vue de défilement qui sera plus grande que son cadre. Il semble que vous essayiez de le faire dans votre code, mais peut-être que vous aviez des contraintes superflues qui rendaient le contentSize trop petit.

Notez également que, comme d'autres l'ont mentionné, avec AutoLayout et UIScrollview, vous ne définissez plus explicitement contentSize. Le système AutoLayout calcule le contentSize en fonction de vos contraintes.

J'ai également trouvé ce chapitre d'ebook très utile pour me faire comprendre comment tout cela fonctionne. J'espère que tout cela aide.

Jamie Forrest
la source
2
MERCI pour l'exemple de projet! Cela fonctionne, et en regardant à travers, je n'ai pas pu trouver de différence avec mon projet au début! J'ai copié les vues dans mon projet, soupçonnant un autre paramètre que les contraintes, mais cela a continué à fonctionner. Cela m'a amené à remarquer que la contrainte de fin du dernier bouton de mon projet a un négatif - devant elle, tandis que la vôtre a une valeur positive! Changer le - en positif a activé le défilement! Lorsque j'affiche la barre d'outils Épingler, il y a deux choix: Utiliser la valeur actuelle du canevas, qui est négative, et la vue Défilement (utiliser la valeur actuelle) qui est positive ...?!
user1459524
Ah oui. La valeur négative rendrait en fait le contentSize de la vue de défilement plus petit, pour correspondre au fait que le bord de fuite doit se terminer avant la fin du bouton. Heureux que l'exemple de projet ait aidé!
Jamie Forrest
Cela a fait beaucoup. Consultez ma réponse mise à jour. La valeur finale devrait en fait être 0 (zéro), semble-t-il.
user1459524
6
C'est triste que nous devions partager des captures d'écran au lieu du code. C'est simplement parce qu'Apple encourage les développeurs à utiliser Builder au lieu de fournir une meilleure API.
Vladimír Slavík
4
Totalement peu intuitif. Les développeurs doivent perdre des heures et des heures à comprendre ce qui se passait dans l'esprit des créateurs de XCode.
Josh
49

Bienvenue LOL au club de stupidité. Je suis l'un des fondateurs. :RÉ

Pour le défilement VERTICAL : le seul moyen de le faire fonctionner (iOS 8, Xcode 6 et mise en page automatique pure) était d'ajouter les contraintes suivantes à ma vue de défilement (toutes liées à la supervision):

  • Largeurs égales
  • Hauteur égale
  • Alignement centre Y
  • Alignement centre X

Ma structure:

  UIView
   - ScrollView
    - Subview
    - Subview
    - Subview
    - Subview
    - ...

Voici le résultat final:

Démo

Voici la configuration:

Installer Plein écran

Et voici le projet .

J'espère que cela éviterait à quelqu'un d'aller dormir à 5 heures du matin. :RÉ

barre oblique inverse-f
la source
Merci beaucoup pour l'aide! Comment avez-vous obtenu la sous-vue de type "sous-vue" ?? Je regarde votre projet dans Xcode 6.2, et il appelle ces petits rectanges "Sous-vue" avec la seule contrainte étant qu'il fait 63px de haut.
Andrew K
1
Salutations! Cette "sous-vue" est en fait un UIVIew. C'est juste un nom ... Vous pouvez taper n'importe quoi ici. Regardez cette image: cl.ly/image/291f1K2N0V3p Sur le sujet des contraintes, les sous-vues ont plus qu'une simple contrainte de hauteur. Consultez la liste complète des contraintes pour ces vues ici: cl.ly/image/3l061i123j2i
backslash-f
1
Je ne parviens toujours pas à faire fonctionner le défilement. J'ai remarqué que vos vues secondaires sont "grisées" dans votre projet. Après avoir fait quelques recherches, il semble que c'est parce que vous utilisez des «classes de taille». Comment cela affecte-t-il le défilement? Existe-t-il un moyen de faire fonctionner le défilement sans utiliser cela?
Andrew K
De plus, comment avez-vous rendu votre supervision tellement plus longue que la durée par défaut? J'essaye d'ajouter des boutons qui apparaîtront "sous le pli" (ou hors écran) mais évidemment je ne peux pas les ajouter au superview si je ne peux pas les faire glisser et les déposer sur le superview car il n'est pas assez grand.
Andrew K
1
après une longue journée de recherche et d'essais de faire cette mise en page de stupidité, j'ai trouvé cette réponse et fonctionne du premier coup .. Merci mec .. vous sauvez ma journée .. j'aimerais pouvoir donner mille votes pour cette réponse ..: )
Bobby Stenly
32

Exemple autonome simple

À en juger par le nombre élevé de votes sur la question et le faible nombre de votes sur les réponses, les gens ne trouvent pas ici de solution compréhensible et rapide. Permettez-moi d’en ajouter un. Ce projet est un exemple autonome réalisé entièrement dans Interface Builder. Vous devriez pouvoir y travailler en 10 minutes ou moins. Ensuite, vous pouvez appliquer les concepts que vous avez appris à votre propre projet.

entrez la description de l'image ici

La question d'origine porte sur les boutons de défilement. Ici, j'utilise juste des UIViews mais ils peuvent représenter la vue que vous aimez. J'ai également choisi le défilement horizontal car les captures d'écran du storyboard sont plus compactes pour ce format. Les principes sont les mêmes pour le défilement vertical, cependant.

Concepts clés

  • Le UIScrollViewne doit utiliser qu'une seule sous-vue. Il s'agit d'un 'UIView' qui sert de vue de contenu pour contenir tout ce que vous souhaitez faire défiler.
  • Faire en sorte que la vue de contenu et le parent de la vue de défilement aient des hauteurs égales pour le défilement horizontal. (Largeurs égales pour le défilement vertical)
  • Assurez-vous que tout le contenu déroulant a une largeur définie et est épinglé de tous les côtés.

Commencer un nouveau projet

Il peut s'agir d'une simple application d'affichage.

Storyboard

Dans cet exemple, nous allons créer une vue de défilement horizontal. Sélectionnez le contrôleur de vue, puis choisissez Forme libre dans l'inspecteur de taille. Faites la largeur 1,000et la hauteur 300. Cela nous donne juste de la place sur le storyboard pour ajouter du contenu qui défilera.

entrez la description de l'image ici

Ajouter une vue de défilement

Ajoutez a UIScrollViewet épinglez les quatre côtés à la vue racine du contrôleur de vue.

entrez la description de l'image ici

Ajouter une vue de contenu

Ajoutez un UIViewcomme sous-vue à la vue de défilement. C'est la clé. N'essayez pas d'ajouter beaucoup de sous-vues à la vue de défilement. Ajoutez simplement un seul UIView. Ce sera votre vue de contenu pour les autres vues que vous souhaitez faire défiler. Épinglez la vue de contenu à la vue de défilement sur les quatre côtés.

entrez la description de l'image ici

Hauteur égale

Maintenant, dans la structure du document, Commandcliquez à la fois sur la vue de contenu et sur la vue parente de la vue de défilement afin de les sélectionner toutes les deux. Ensuite, définissez les hauteurs pour qu'elles soient égales ( Controlfaites glisser de la vue de contenu vers la vue de défilement). C'est également la clé. Comme nous faisons défiler horizontalement, la vue du contenu de la vue de défilement ne saura pas à quelle hauteur elle devrait être à moins que nous ne la définissions de cette manière.

entrez la description de l'image ici

Remarque:

  • Si nous faisions défiler le contenu verticalement, nous définirions la largeur de la vue de contenu pour qu'elle soit égale à la largeur du parent de la vue de défilement.

Ajouter du contenu

Ajoutez trois UIViews et donnez-leur toutes les contraintes. J'ai utilisé des marges de 8 points pour tout.

entrez la description de l'image ici

Contraintes:

  • Vue verte: épinglez les bords supérieur, gauche et inférieur. Faites la largeur 400.
  • Vue rouge: épinglez les bords supérieur, gauche et inférieur. Faites la largeur 300.
  • Vue violette: épinglez les quatre bords des bords. Faites la largeur quel que soit l'espace restant (268 dans ce cas).

La définition des contraintes de largeur est également essentielle pour que la vue de défilement sache la largeur de sa vue de contenu.

Fini

C'est tout. Vous pouvez exécuter votre projet maintenant. Il devrait se comporter comme l'image défilante en haut de cette réponse.

Pour le défilement vertical, permutez simplement toutes les directions de largeur et de hauteur dans cet exemple (testé et fonctionnel).

Une étude plus approfondie

Suragch
la source
9

Le contentSize est implicitement défini en appliquant les contraintes à l'intérieur de UIScrollView.

Par exemple, si vous avez un UIScrollView à l'intérieur d'un UIView, il ressemblera à ceci (comme je suis sûr que vous le savez):

    UIView *containerView               = [[UIView alloc] init];
    UIScrollView *scrollView            = [[UIScrollView alloc] init];
    [containerView addSubview:scrollView];
    containerView.translatesAutoresizingMaskIntoConstraints = NO;
    scrollView.translatesAutoresizingMaskIntoConstraints    = NO;
    NSDictionary *viewsDictionary       = NSDictionaryOfVariableBindings(containerView, scrollView);

    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|"
                                                                          options:kNilOptions
                                                                          metrics:nil
                                                                            views:viewsDictionary]];
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|"
                                                                          options:kNilOptions
                                                                          metrics:nil

Cela définira le scrollView pour remplir la taille du containerView (donc le containerView devra être d'une certaine taille).

Vous pouvez ensuite ajuster le contentSize de UIScrollView en le définissant implicitement pour qu'il soit suffisamment grand pour contenir les boutons comme ceci:

    UIButton *buttonA                   = [[UIButton alloc] init];
    UIButton *buttonB                   = [[UIButton alloc] init];
    UIButton *buttonC                   = [[UIButton alloc] init];
    [scrollView addSubview:buttonA];
    [scrollView addSubview:buttonB];
    [scrollView addSubview:buttonC];
    buttonA.translatesAutoresizingMaskIntoConstraints       = NO;
    buttonB.translatesAutoresizingMaskIntoConstraints       = NO;
    buttonC.translatesAutoresizingMaskIntoConstraints       = NO;

    viewsDictionary                     = NSDictionaryOfVariableBindings(scrollView, buttonA, buttonB, buttonC);

    [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[buttonA]-|"
                                                                       options:kNilOptions
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
    [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[buttonA]-[buttonB]-[buttonC]-|"
                                                                       options:NSLayoutFormatAlignAllBaseline
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
Infinity James
la source
Donc, j'ai défini les contraintes entre le scrollView et les boutons, et non le containerView et les boutons? Je pense que c'est à peu près la seule différence que je porte entre votre code et ce que je fais via le storyboard en ce moment.
user1459524
Je n'ai réalisé qu'après la deuxième lecture que vous configurez un CONTAINERview et non un CONTENTview. Sur la base de votre code, j'ai tout recréé exactement dans le storyboard, et il ne défile pas. Je modifierai ma question avec quelques captures d'écran.
user1459524
1
Il s'avère donc que ma tentative de recréer le code dans le storyboard n'était pas correcte à 100%. La valeur de fin du dernier bouton doit être exactement zéro, reflétant H: | - [buttonA] - [buttonB] - [buttonC] - | ce qui n'est pas très évident lorsque vous travaillez dans le storyboard (ou du moins ne l'était pas pour moi) mais maintenant après coup semble trivial. J'adore la mise en page automatique, mais ces petites choses vous
attirent
Ce que @ user1459524 a mentionné était un problème pour moi. Ma vue de dessous était un bouton et la contrainte du bas était de -32 par IB. J'ai mis cela à 0 et il a été mis à jour dans IB pour être Bottom Space à: superview. Cela fonctionnera, aussi il semble que tant que vous êtes du côté positif, cela fonctionne. On dirait que cela peut être un bogue avec IB. J'espère que cela aide quelqu'un d'autre. J'ai également supprimé toutes les vues et recâblé, ce qui aide lorsque je tente de les présenter, et cela ne prend généralement pas longtemps.
Michael
8

Il y a tellement de questions sur l'utilisation de la mise en page automatique avec UIScrollView, le point clé que nous ignorons est que les vues internes de UIScrollView font des contraintes sur la vue de contenu mais pas sur UIScrollView lui-même. Reportez-vous à la note technique TN2154 , vous pouvez trouver:

La classe UIScrollView fait défiler son contenu en modifiant l'origine de ses limites. Pour que cela fonctionne avec la mise en page automatique, les bords supérieur, gauche, inférieur et droit d'une vue de défilement désignent désormais les bords de sa vue de contenu.

La figure suivante montre que: entrez la description de l'image ici

Vous pouvez trouver que l'espace de fin est de 500 points, si la contrainte est appliquée à UIScrollView, la vue sera mal placée et devrait être mise à jour son cadre. Cependant, aucun avertissement et aucune erreur. Parce que toutes les contraintes sont contre la vue du contenu.

UIScrollView calculera la taille de la vue de contenu en fonction des contraintes des vues intérieures. (Pour l'exemple, la taille du contenu: largeur = 100 (espace de début) + 200 (largeur de la vue) + 500 (espace de fin), hauteur = 131 (espacement du haut) + 200 (hauteur) + 269 (espacement du bas))

Comment ajouter des contraintes pour les vues dans UIScrollView:

  1. Imagerie des positions des vues dans la vue de contenu.
  2. Ajoutez un espacement en haut, à droite, en bas et à gauche aux bords de la vue de contenu, ainsi que la largeur et la hauteur de ces vues.

Et tout est fait.

Un moyen simple de gérer la mise en page automatique avec scrollview consiste à ajouter une vue de conteneur contenant toutes les sous-vues dans la vue de défilement.

Conclusion: le point clé pour comprendre AutoLayout avec UIScrollView est que les vues internes créent des contraintes contre la vue de contenu mais pas UIScrollView lui-même.

code d'exemple joint

Danyun Liu
la source
5

La solution suivante a fonctionné pour moi pour scrollView avec autolayout et sans contentSize :

  1. Faites glisser et déposez un scrollView vers viewController et appliquez les contraintes pour couvrir l'espace souhaité.
  2. Faites glisser et déposez un UIView à l'intérieur de scrollView et faites-le couvrir tout l'espace de scrollView et appliquez des contraintes pour qu'il soit en haut, à gauche, à droite, en bas de scrollView.
  3. Définissez la hauteur (et la largeur si le défilement horizontal est requis) de la vue intérieure selon le besoin de défilement. Cette partie peut également être effectuée à partir du code si nécessaire.
  4. Critique . Après avoir défini la hauteur sur une valeur élevée au point (3), revenez au point (2) et assurez-vous de remettre les valeurs supérieure, gauche, droite et inférieure à zéro car Xcode peut les avoir modifiées pour vous lorsque vous forcez a changé la hauteur dans (3).

Et tu as fini. Maintenant, vous pouvez ajouter n'importe quel nombre de contrôles sur cette vue et appliquer les contraintes pertinentes les unes aux autres (qui ne semblent pas fonctionner sans cette vue). Si vous ne souhaitez pas utiliser cette vue, vous devrez appliquer des contraintes pour chaque contrôle lié à scrollView (non liés les uns aux autres).


Le conseil écrasant ..............

Critique . Disons que pour plus de clarté, l'UIScrollView a une largeur de 1000 et une hauteur de 100. (En fait, normalement, ces valeurs seraient dynamiques, bien sûr, en fonction de la largeur de l'appareil, etc. Mais pour l'instant, disons simplement 1000 de large et 100 de haut.) Disons que vous faites un défilement horizontal. Mettez donc un UIView dans UIScrollView. (C'est la "vue de contenu".) Définissez les quatre contraintes de la vue de contenu haut, bas, début, fin, sur la vue de défilement. Faites-les tous à zéro, même si cela semble faux. Définissez la hauteur du contenu UIView sur 100 et oubliez cela. Maintenant: vous voulez faire défiler horizontalement, alors définissez la largeur de la vue du contenu sur 1225.

Notez que la largeur de la vue de contenu est maintenant 225 plus grande que la largeur de la vue de défilement parent. C'est OK: en fait, vous DEVEZ le faire. Notez que

... vous ne définissez PAS la largeur de fin sur moins de 225 ...

vous penseriez que vous devez "faire correspondre" les largeurs comme vous le feriez normalement . Mais si vous faites cela, cela ne fonctionnera pas du tout.

Vous devez définir les nombres de début et de fin sur ZERO , jamais négatifs (même si la largeur est "plus grande")

Fait intéressant, vous pouvez en fait définir les nombres de début / de fin sur n'importe quelle valeur positive (essayez de dire «50») et cela vous donne une sorte de marge du rebond. (Cela a souvent l'air génial: essayez-le.) Toute valeur négative à l'une ou l'autre extrémité "cassera silencieusement".

Notez que, de manière exaspérante, souvent Xcode (à partir de 7.3.1 de toute façon),

va "utilement" définir ces valeurs pour vous sur des nombres négatifs!

car il essaie de les compter automatiquement pour vous. Si c'est le cas, il se cassera silencieusement. Définissez les quatre valeurs sur zéro dans la première instance. Et définissez la largeur de la vue du contenu beaucoup plus large que le "1000" dans l'exemple.


Modifié: j'ai fini par utiliser UITableView au lieu de UIScrollView pour la plupart de mes besoins. Comme tableView me semble beaucoup plus flexible et dynamique.

Zeeawan
la source
C'est en fait la meilleure réponse ici. Merci!
Fattie
4

Je suppose que vous rencontrez des problèmes avec le contentSize. Consultez ce billet de blog sur la façon de gérer le contentSizelors de l'utilisation d'une approche de mise en page automatique «pure». L'essentiel est que vos contraintes définissent implicitement la taille du contenu. Vous ne le définissez JAMAIS explicitement lors de l'utilisation de la mise en page automatique. J'ai joint un exemple de projet à la fin de l'article de blog pour montrer comment cela fonctionne

Edward Huynh
la source
3

Il y a un élément dans les notes techniques que vous avez peut-être examiné. Vous pouvez définir implicitement la taille du contenu d'une vue de défilement à l'aide de contraintes fixées aux bords de la vue de défilement.

Voici un exemple simple. Créez un storyboard avec une vue, qui a une vue de défilement. Définissez ces contraintes de vues de défilement pour qu'elles correspondent à la taille de la vue dans laquelle vous les placez.

À l'intérieur de cette vue de défilement, ajoutez une vue unique. Définissez explicitement la taille de cette vue à l'aide de contraintes (et assurez-vous que cette taille est plus grande que la vue de défilement).

Ajoutez maintenant quatre contraintes supplémentaires à cette vue intérieure en verrouillant les quatre bords de la vue intérieure à sa vue de défilement parente. Ces quatre contraintes entraîneront l'expansion de la taille du contenu pour s'adapter à la vue intérieure.

Si vous souhaitez ajouter plusieurs vues à une vue de défilement, par exemple disposées horizontalement, vous verrouillez le côté gauche de la première sous-vue à gauche de la vue de défilement, verrouillez les sous-vues les unes aux autres horizontalement et à droite. côté de la dernière vue secondaire à droite de la vue de défilement. Ces contraintes forceraient la taille du contenu de la vue de défilement à se développer pour s'adapter à toutes les sous-vues et à leurs contraintes.

Travis
la source
3

Si votre question est "Comment puis-je mettre un tas de UITextFields dans un UIScrollView à défilement vertical de telle sorte qu'ils se déplacent hors du chemin du clavier lorsqu'ils ont le focus", la meilleure réponse est:

Ne fais pas ça.

Utilisez plutôt un UITableViewController avec des cellules statiques.

Vous obtenez ce comportement de défilement hors du chemin gratuitement, ET tous les inserts de contenu fonctionnent simplement si votre contrôleur de vue est affiché dans un UINavigationController.

Robert Atkins
la source
3

Vous devez organiser votre mise en page comme ceci
ViewControllerViewcontient ScrollView, ScrollViewcontient ContainerView, ContainerViewcontient 2Labels
entrez la description de l'image ici

Puis suivez 3 étapes pour faire ScrollViewdéfiler votre can

  1. Réglage de la ScrollViewbroche (haut / droite / bas / gauche) surViewControllerView
    • Réglage de la ContainerViewbroche (haut / droite / bas / gauche) surScrollView
    • Définir Horizontally in Container( ne pas définir Vertically in Container)
    • Label1broche ( haut / droite / gauche) àContainerView
    • Label1broche (droite / gauche / bas ) vers ContainerViewet haut versLabel1

entrez la description de l'image ici

ICI est le projet de démonstration

J'espère que cette aide

Phan Van Linh
la source
1

L'approche de mise en page automatique pure fonctionne à merveille, mais la configuration est assez pénible si vous migrez à partir d'une mise en page non automatique. Je l'ai fait plusieurs fois maintenant et j'ai quelques conseils généraux:

  • Commencez petit: même si cela signifie recréer vos vues de storyboard, commencez avec seulement quelques éléments et construisez vos vues lentement, en veillant à tester que le défilement fonctionne après avoir ajouté quelques éléments.
  • Désactivez translatesAutoresizingMaskIntoConstraints sur tout: cela a toujours été la cause des conflits de contraintes pour moi.
  • Définissez correctement vos contraintes UIScrollView: assurez-vous que la vue de défilement est connectée de tous les côtés à la vue parente, sinon elle ne se développera pas du tout.
pseudo
la source
1

Après un certain temps à traiter ce problème, j'ai finalement trouvé une solution. Je travaille avec des storyboards de taille de classe universelle (600x600). J'ai créé un UIView (contentView) de la taille du scrollView et créé des contraintes pour Top, Bottom, Leading et Trailing pour le scrollView. Ensuite, j'ai coupé manuellement la taille du contentView à 600x600. Le storyboard a cessé d'essayer de tout redimensionner et j'ai pu travailler mais la vue était horrible sur le vrai appareil ou le simulateur. J'ai réalisé 2 prises de contrainte de cette taille coupée.

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewWidthConstraint; 
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewHeightConstraint;

Puis dans viewDidLoad

CGSize viewSize = self.view.frame.size;
self.contentViewWidthConstraint.constant = viewSize.width;
self.contentViewHeightConstraint.constant = viewSize.height;

Fonctionne très bien.

Cristian Pena
la source
1

J'ai passé des jours à essayer de trouver une solution sur la façon d'utiliser la mise en page automatique pour afficher une vue de défilement intégrée, pour centrer la vue de défilement dans l'écran visible, qui fonctionne sur tous les appareils / dimensions d'écran ainsi qu'avec la rotation de l'écran.

J'ai passé des jours à essayer de le faire avec Autolayout uniquement, et je me suis rapproché mais jamais assez. Donc, à la fin, j'ai dû ajouter 3 lignes de code par écran également, dans viewDidLoad.

Voir la solution ci-dessous:

  1. Créez la vue de défilement et remplissez-la avec les objets de votre choix
  2. Activer la disposition automatique
  3. Centrez ensuite le ScrollView verticalement et horizontalement Centre ScrollView
  4. Sélectionnez la vue puis `` Ajouter les contraintes manquantes '' - cela fait alors son truc
  5. Le résultat est que de nombreuses contraintes sont générées. Il y en a 2 nouveaux créés pour la vue: 'Horiz space scrollview to View' et 'Vert space scrollview to view' ou vice-versa.
  6. Supprimez la «vue de défilement de l'espace horizontal vers la vue» pour vous retrouver maintenant avec 3 contraintes sur la vue. Le 2 pour entrer dans la vue de défilement dans la vue et celui pour définir un espace vertical entre la vue de défilement et la vue
  7. Maintenant, liez la contrainte Vert à votre code en cliquant et Ctrl en la faisant glisser vers le fichier d'en-tête et en créant un IBOutlet NSLayoutConstraint (j'ai appelé mine constraintVertVtoSV)
  8. Allez maintenant dans le fichier .m et ajoutez ces lignes de code dans viewDidLoad (jouez avec la quantité de remplissage pour obtenir le bon centrage vert)

    if (IPAD)

    {self.constraintVertVtoSV.constant = 150,0; }

  9. cela devrait maintenant fonctionner sur tous les appareils et être correctement centré et toujours défiler correctement.

Gars
la source
1

Si, comme moi, vous utilisez simplement du contenu statique sans contraintes à l'intérieur de la sous-vue, comme vous pouvez le faire comme ceci:

override func viewDidLayoutSubviews() {
    scrollView.contentSize = CGSizeMake(320, 800)
}
Antzi
la source
1

Problème similaire que j'ai aujourd'hui avec iOS 8.4, Xcode 6.4

Là, une vue contenant une vue de défilement, contenant un contentView (UIView) contenant des sous-vues.

Tout est mise en page automatique partout. Les bords de la vue de défilement sont épinglés aux bords de la vue parent avec des contraintes. Les bords de la vue de contenu sont épinglés aux bords de la vue de défilement avec des contraintes.

À l'origine, la vue de contenu refusait de prendre la taille totale de la vue de défilement. J'ai dû ajouter une contrainte supplémentaire sur la vue du contenu pour que sa largeur corresponde à la vue de défilement parent. Ou je pourrais définir une contrainte contentView.centerX == scrollView.centerX. L'un ou l'autre de ceux-ci en plus d'épingler les bords a soudainement rendu le contenu affiché correctement.

// Either one of these additional constraints are required to get autolayout to correctly layout the contentView. Otherwise contentView size is its minimum required size
scrollView.addConstraint(NSLayoutConstraint(item: contentView, attribute: .CenterX, relatedBy: .Equal, toItem: scrollView, attribute: .CenterX, multiplier: 1.0, constant: 0))
scrollView.addConstraint(NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: 0.0))

Épingler les bords de la vue de contenu à la vue de défilement à l'aide des contraintes visuelles du formulaire,

let cvConstraints = ["H:|[contentView]|", "V:|[contentView]|"]

J'utilise une routine pour parcourir le tableau et les ajouter au scrollView.

David
la source
1

J'ai fait face à un problème similaire. J'ai défini chaque contrainte et je me suis toujours demandé pourquoi il redimensionnait encore certaines sous-vues. Ma solution a été de régler clipsToBounds sur YES.

i89
la source
1

En rapide, vous pouvez utiliser cette solution de travail.

Contraintes

ScrollView: Avant, Arrière, Haut, Bas = Vue d'ensemble

ContentView: Début, Fin, Haut, Bas = ScrollView. Hauteur fixe / relative au contenu.

Vous pouvez définir la contrainte de largeur (contentView) pour égaliser les vues de défilement superview, mais sélectionnez supprimer supprimer au moment de la génération, car vous ajouterez cette contrainte par programme. C'est juste pour que l'IB ne se plaint pas d'avertissements.

extension UIView {

    func setupContentViewForViewWithScroll(contentView vwContent : UIView) {
        //Set constraint for scrollview content
        let constraint = NSLayoutConstraint(item: vwContent, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.bounds.size.width)
        vwContent.addConstraint(constraint)
        self.layoutSubviews()
    }

}

Et dans View Controller, viewDidLayoutSubviewsj'appelle simplement cette méthode:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    self.view.setupContentViewForViewWithScroll(contentView: vwContent)
}
Ibrahim Yildirim
la source
0

Je sais que c'est une solution profane et non ce qu'Apple suggère dans le docu, mais cela a fonctionné pour moi deux fois, avec un contenu différent et peut être configuré très rapidement: dans le contrôleur de vue storyboard, insérez UIView. Dans UIView, insérez une vue de tableau, dynamique, 0 cellule de prototype, style simple ou groupé. Dans la vue de tableau, insérez une vue de défilement, dans la vue de défilement, insérez du contenu. C'est tout, pas de paramètres dans le contrôleur de vue personnalisé.

Rinaldo
la source