139 votes

Comment adapter automatiquement la taille d'un UIScrollView à son contenu ?

Y a-t-il un moyen de faire un UIScrollView s'ajuste automatiquement à la hauteur (ou à la largeur) du contenu qu'il fait défiler ?

Quelque chose comme :

[scrollView setContentSize:(CGSizeMake(320, content.height))];

316voto

leviathan Points 5207

La meilleure méthode que j'ai rencontrée pour mettre à jour la taille du contenu d'un fichier de type UIScrollView en fonction des sous-vues qu'il contient :

Objectif-C

CGRect contentRect = CGRectZero;

for (UIView *view in self.scrollView.subviews) {
    contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect.size;

Swift

let contentRect: CGRect = scrollView.subviews.reduce(into: .zero) { rect, view in
    rect = rect.union(view.frame)
}
scrollView.contentSize = contentRect.size

13 votes

Je faisais tourner ça dans viewDidLayoutSubviews pour que la mise en page automatique se termine, dans iOS7, cela a bien fonctionné, mais en testant iOS6, la mise en page automatique n'a pas terminé le travail pour une raison quelconque, et j'avais des valeurs de hauteur erronées. viewDidAppear Je voulais juste signaler que quelqu'un pourrait en avoir besoin. Merci.

1 votes

Avec l'iPad iOS6, il y avait un mystérieux UIImageView (7x7) dans le coin inférieur droit. Je l'ai filtré en n'acceptant que les composants UI (visible && alpha), et ça a marché. Je me demande si cette imageView est liée aux barres de défilement, ce n'est certainement pas mon code.

6 votes

Faites attention lorsque les indicateurs de défilement sont activés ! Un UIImageView sera automatiquement créé pour chacun d'eux par le SDK. Vous devez en tenir compte, sinon la taille de votre contenu sera incorrecte. ( voir stackoverflow.com/questions/5388703/ )

73voto

emenegro Points 1316

UIScrollView ne connaît pas automatiquement la hauteur de son contenu. Vous devez calculer la hauteur et la largeur par vous-même

Faites-le avec quelque chose comme

CGFloat scrollViewHeight = 0.0f;
for (UIView* view in scrollView.subviews)
{
   scrollViewHeight += view.frame.size.height;
}

[scrollView setContentSize:(CGSizeMake(320, scrollViewHeight))];

Mais cela ne fonctionne que si les vues sont l'une en dessous de l'autre. Si vous avez une vue l'une à côté de l'autre, vous ne devez ajouter que la hauteur d'une seule vue si vous ne voulez pas que le contenu du défilement soit plus grand qu'il ne l'est réellement.

0 votes

Pensez-vous que quelque chose comme ça pourrait fonctionner aussi bien ? CGFloat scrollViewHeight = scrollView.contentSize.height ; [scrollView setContentSize :(CGSizeMake(320, scrollViewHeight))] ; BTW, n'oubliez pas de demander la taille puis la hauteur. scrollViewHeight += view.frame.size.height

0 votes

L'initialisation du scrollViewHeight à la hauteur rend le défileur plus grand que son contenu. Si vous faites cela, n'ajoutez pas la hauteur des vues visibles à la hauteur initiale du contenu du scroller. Bien que vous ayez peut-être besoin d'un écart initial ou d'autre chose.

21 votes

Ou simplement le faire : int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame)‌​, y))];

44voto

Adam Waite Points 2242

Solution si vous utilisez la mise en page automatique :

  • Définir translatesAutoresizingMaskIntoConstraints à NO sur toutes les vues impliquées.

  • Positionnez et dimensionnez votre vue défilante avec des contraintes externes à la vue défilante.

  • Utilisez les contraintes pour disposer les sous-vues dans la vue défilante, s'assurer que les contraintes sont liées aux quatre bords de la vue défilante et ne dépendent pas de la vue défilante pour obtenir leur taille.

Source : https://developer.apple.com/library/ios/technotes/tn2154/_index.html

12 votes

Je pense que c'est la vraie solution dans le monde où tout se passe avec la mise en page automatique. En ce qui concerne les autres solutions : Qu'est-ce que... vous êtes sérieux en calculant la hauteur et parfois la largeur de chaque vue ?

0 votes

Merci de partager cela ! Cela devrait être la réponse acceptée.

5 votes

Cela ne fonctionne pas lorsque vous souhaitez que la hauteur du scrollview soit basée sur la hauteur de son contenu. (par exemple une popup centrée dans l'écran où vous ne voulez pas faire défiler le contenu avant une certaine hauteur).

35voto

richy Points 690

J'ai ajouté ceci à la réponse d'Espuz et de JCC. Elle utilise la position y des sous-vues et n'inclut pas les barres de défilement. Modifier Utilise le bas de la sous-vue la plus basse qui est visible.

+ (CGFloat) bottomOfLowestContent:(UIView*) view
{
    CGFloat lowestPoint = 0.0;

    BOOL restoreHorizontal = NO;
    BOOL restoreVertical = NO;

    if ([view respondsToSelector:@selector(setShowsHorizontalScrollIndicator:)] && [view respondsToSelector:@selector(setShowsVerticalScrollIndicator:)])
    {
        if ([(UIScrollView*)view showsHorizontalScrollIndicator])
        {
            restoreHorizontal = YES;
            [(UIScrollView*)view setShowsHorizontalScrollIndicator:NO];
        }
        if ([(UIScrollView*)view showsVerticalScrollIndicator])
        {
            restoreVertical = YES;
            [(UIScrollView*)view setShowsVerticalScrollIndicator:NO];
        }
    }
    for (UIView *subView in view.subviews)
    {
        if (!subView.hidden)
        {
            CGFloat maxY = CGRectGetMaxY(subView.frame);
            if (maxY > lowestPoint)
            {
                lowestPoint = maxY;
            }
        }
    }
    if ([view respondsToSelector:@selector(setShowsHorizontalScrollIndicator:)] && [view respondsToSelector:@selector(setShowsVerticalScrollIndicator:)])
    {
        if (restoreHorizontal)
        {
            [(UIScrollView*)view setShowsHorizontalScrollIndicator:YES];
        }
        if (restoreVertical)
        {
            [(UIScrollView*)view setShowsVerticalScrollIndicator:YES];
        }
    }

    return lowestPoint;
}

1 votes

Merveilleux ! Juste ce dont j'avais besoin.

2 votes

Je suis surpris qu'une méthode comme celle-ci ne fasse pas partie du cours.

0 votes

Pourquoi avez-vous fait self.scrollView.showsHorizontalScrollIndicator = NO; self.scrollView.showsVerticalScrollIndicator = NO; au début et self.scrollView.showsHorizontalScrollIndicator = YES; self.scrollView.showsVerticalScrollIndicator = YES; à la fin de la méthode ?

4voto

paxx Points 494

Vous pouvez obtenir la hauteur du contenu à l'intérieur de UIScrollView en calculant quel enfant "atteint le plus loin". Pour calculer cela, vous devez prendre en considération l'origine Y (départ) et la hauteur de l'élément.

float maxHeight = 0;
for (UIView *child in scrollView.subviews) {
    float childHeight = child.frame.origin.y + child.frame.size.height;
    //if child spans more than current maxHeight then make it a new maxHeight
    if (childHeight > maxHeight)
        maxHeight = childHeight;
}
//set content size
[scrollView setContentSize:(CGSizeMake(320, maxHeight))];

En procédant de cette manière, les éléments (vues secondaires) ne doivent pas être empilés directement les uns sous les autres.

0 votes

Vous pouvez également utiliser cette doublure à l'intérieur de la boucle : maxHeight = MAX(maxHeight, child.frame.origin.y + child.frame.size.height) ;)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X