UIScrollView ne défile pas


128

J'ai un UIScrollViewqui contient beaucoup de UIImageViews, UILabels, etc ... les étiquettes sont beaucoup plus longues que le UIScrollView, mais quand je lance l'application, je ne peux pas cliquer et faire défiler vers le bas ...

Pourquoi cela pourrait-il être?

Merci


Nouveau 26/03/2013 Je suis tombé sur un moyen plus simple de le faire sans code (paramètre contentSize) stackoverflow.com/a/15649607/1705353
Dickey Singh

Réponses:


169

Il est toujours bon d'afficher un extrait de code fonctionnel complet:

// in viewDidLoad (if using Autolayout check note below):

UIScrollView *myScrollView;
UIView *contentView;
// scrollview won't scroll unless content size explicitly set

[myScrollView addSubview:contentView];//if the contentView is not already inside your scrollview in your xib/StoryBoard doc

myScrollView.contentSize = contentView.frame.size; //sets ScrollView content size

Swift 4.0

let myScrollView
let contentView

// scrollview won't scroll unless content size explicitly set

myScrollView.addSubview(contentView)//if the contentView is not already inside your scrollview in your xib/StoryBoard doc

myScrollView.contentSize = contentView.frame.size //sets ScrollView content size

Je n'ai pas trouvé de moyen de définir contentSize dans IB (à partir de Xcode 5.0) .

Remarque: Si vous utilisez Autolayout, le meilleur endroit pour mettre ce code est à l'intérieur de la -(void)viewDidLayoutSubviewsméthode.


12
N'oubliez pas de définir myScrollView.delegate = selfAUSSI, si cela ne fonctionne toujours pas, la réponse ci-dessous celle-ci a de BONS conseils (allez dans votre xib / StoryBoard et assurez-vous que "AutoLayout" est désactivé). Astuce de pro: Vous pouvez également inclure <UIScrollViewDelegate>dans votre fichier .h si vous souhaitez faire des choses comme faire défiler par programme votre UIScrollView.
Albert Renshaw

1
@AlbertRenshaw vous auriez dû ajouter une réponse afin que j'aurais pu vous donner un +1 :) AutoLayout était le problème avec moi .... m'a rendu fou pendant environ 4 heures.
logixologist

2
Mettre du code viewDidLayoutSubviewsa fonctionné pour moi.
Amr Lotfy

Pour moi, le problème était qu'il n'avait pas besoin de faire défiler, car tout tenait à l'écran.
Daniel Springer

122

Si vous ne pouvez pas faire défiler la vue même après avoir défini correctement contentSize , assurez-vous de décocher "Utiliser la mise en page automatique" dans Interface Builder -> Inspecteur de fichiers.


165
Vous pouvez également définir contentSize dans viewDidLayoutSubviews:, et il sera appliqué une fois la mise en page automatique terminée.
Chris Vasselli

2
@ "Chris Vasselli" a réglé mon problème .. GR8 .. :-)
Ayaz

3
Le commentaire de Chris devrait être une réponse distincte!
ninjaneer

1
Merci beaucoup Chris Vasselli! Avec la mise en page automatique activée, cela ne fonctionnera pas dans viewDidLoad mais c'est le cas avec viewDidLayoutSubviews!
Romain

1
Woah, je n'avais jamais remarqué tous ces commentaires avant! Heureux d'avoir pu aider beaucoup d'entre vous! Je viens de publier une réponse séparée, donc j'espère qu'elle sera plus facile à trouver.
Chris Vasselli

68

Vous devez définir la contentSizepropriété de la vue de défilement pour qu'elle défile correctement.

Si vous utilisez autolayout, vous devez définir contentSizedans viewDidLayoutSubviewsafin qu'il soit appliqué après les finalise autolayout.

Le code pourrait ressembler à ceci:

-(void)viewDidLayoutSubviews
{
    // The scrollview needs to know the content size for it to work correctly
    self.scrollView.contentSize = CGSizeMake(
        self.scrollContent.frame.size.width,
        self.scrollContent.frame.size.height + 300
    );
}

Merci une tonne .. Cela a fonctionné parce que pour une raison quelconque, même lorsque je règle la valeur de contentSizeà la taille de contentView, la taille de scrollView et contentView semble être définie comme la même. Mais régler la hauteur de la contentSizeà une valeur supérieure à la hauteur de contentView, cela a fonctionné.
Skywalker

viewDidLayoutSubviewspeut être appelé plusieurs fois au cours d'un cycle de vie, vous courez donc le risque d'augmenter la hauteur plus grande que prévu.
anon_nerd

@anon_nerd vérifie simplement s'il a déjà été appelé et n'ajoute que de la hauteur sinon
Daniel Springer

45

La réponse ci-dessus est correcte - pour que le défilement se produise, il est nécessaire de définir la taille du contenu.

Si vous utilisez le générateur d'interface, une façon intéressante de le faire est d'utiliser les attributs d'exécution définis par l'utilisateur. Par exemple:

entrez la description de l'image ici


cela n'a rien fait pour moi.
coolcool1994

4
Oups, l'image montre {0, 0}, mais vous devez bien sûr mettre des nombres suffisamment grands. . cette approche ne fonctionnera que pour les vues simples où vous connaissez la taille du contenu à l'avance. . . (en fait, pour les vues complexes, je recommande de toute façon du code pur).
Jasper Blues

Beaucoup moins hacky que de le faire par programmation. Je vous remercie!
Jake Stoeffler

1
@JakeStoeffler Bienvenue! :) Lorsque j'utilise IB, j'aime garder toute la configuration (non fragmentée). Mais lorsque les choses deviennent complexes (widgets de vue réutilisables; adaptateurs de modèle, manipulations de couches; CAAnimations, etc.), je préfère les vues entièrement programmatiques. . . plus couramment.
Jasper Blues

J'ai essayé cela, fonctionne lorsque la vue apparaît, mais lors du changement d'orientation, le contentSize défini sur l'écran ci-dessus est ignoré et mon journal indique que contentSize est reculé 0,0. Une idée de comment résoudre ce problème?
Shoogle

40

Essayez de redimensionner la taille du contenu à des nombres énormes. Je ne pouvais pas comprendre pourquoi ma vue de défilement ne défile pas même lorsque la taille de son contenu semble être plus grande que la taille de contrôle. J'ai découvert que si la taille du contenu est plus petite que nécessaire, cela ne fonctionne pas également.

self.scrollView.contentSize = CGSizeMake(2000, 2000);

Au lieu de 2000, vous pouvez mettre vos propres grands chiffres. Et si cela fonctionne, cela signifie que la taille de votre contenu n'est pas assez grande lorsque vous redimensionnez.

Le délégué n'est pas nécessaire pour que la vue de défilement fonctionne.


2
Genius - un moyen si simple de vérifier ce qui se passe. Merci beaucoup!
The Crazy Chimp

13

Assurez-vous que la propriété contentSize de la vue de défilement est définie sur la taille correcte (c'est-à-dire, suffisamment grande pour englober tout votre contenu).


1
dois-je faire cela par programme? ou puis-je le faire dans IB?
Mark

Si vous utilisez IB, vous pouvez le configurer à partir de là - voir ci-dessous. . (Réponse séparée, donc je peux inclure des photos).
Jasper Blues

7

Décocher "Utiliser la mise en page automatique" a fait l'affaire pour moi.

Environnement: xCode 5.0.2 Storyboards ios7


5

Dans mon cas, j'ai dû définir delaysContentTouchessur true car les objets à l'intérieur du scrollView capturaient tous les événements tactiles et se géraient eux-mêmes plutôt que de laisser le scrollView le gérer.


J'ai le même problème. Le problème pour moi est qu'en définissant delayContentTouches sur true, vous obtiendrez des dessins de qualité inférieure avec un crayon pomme. Mais c'est un cas limite :) dans la plupart des cas, cela résout le problème
RomOne

4

Définit la contentSizepropriété de la méthode UIScrollviewin ViewDidLayoutSubviews. Quelque chose comme ça

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    scrollView.contentSize = CGSizeMake(view.frame.size.width, view.frame.size.height)
}

3

L'idée de pourquoi la vue de défilement ne défile pas parce que vous définissez la taille du contenu pour le défilement inférieure à la taille de la vue de défilement, ce qui est faux. Vous devez définir la taille du contenu plus grande que la taille de votre vue de défilement pour la parcourir tout en faisant défiler.

La même idée avec le zoom, vous définissez les valeurs min et max pour le zoom qui seront appliquées par l'action de zoom.

Bienvenue :)


3

Un petit ajout, tous ci-dessus sont les raisons réelles pour lesquelles votre vue de défilement peut ne pas défiler, mais parfois sans réfléchir, cela pourrait être la raison spécialement lorsque la vue de défilement est ajoutée via le code et non IB, vous avez peut-être ajouté vos sous-vues à la vue parente et non à la vue de défilement cela fait que la sous-vue ne défile pas

et gardez la taille du contenu définie et plus grande que le cadre de vue parent (duhh !!)


3

Je l'ai fait fonctionner à mon premier essai. Avec mise en page automatique et tout, aucun code supplémentaire. Ensuite, une vue de collection est devenue banane, plantant au moment de l'exécution, je n'ai pas trouvé ce qui n'allait pas, alors je l'ai supprimée et recréée (j'utilise Xcode 10 Beta 4. Cela ressemblait à un bug) et puis le défilement avait disparu. La vue Collection fonctionnait à nouveau, cependant!

Plusieurs heures plus tard ... c'est ce qui a résolu le problème pour moi. J'avais la disposition suivante:

UIView

  • Zone protégée
  • Vue de défilement
    • Vue du contenu

Tout est dans les contraintes. La zone de sécurité est automatiquement définie par le système. Dans le pire des cas, supprimez toutes les contraintes pour les vues de défilement et de contenu et ne laissez pas IB les réinitialiser / les créer pour vous. Faites-les manuellement, cela fonctionne.

  • Pour la vue de défilement, j'ai fait: Alignez Trailing / Top to Safe Area. Largeur / hauteur égale à la zone sûre .
  • Pour la vue Contenu, j'ai fait: Aligner Trailing / Leading / Top / Bottom sur Superview (la vue de défilement)

fondamentalement, le concept est d'avoir une vue de contenu adaptée à Scrollview, qui correspond à la zone de sécurité.

Mais en tant que tel, cela n'a pas fonctionné. L'affichage du contenu a manqué la hauteur. J'ai essayé tout ce que je pouvais et le seul à faire l'affaire a été une hauteur de vue de contenu créée en faisant glisser la vue de contenu ... vers elle-même . Cela a défini une hauteur fixe, dont la valeur a été calculée à partir de la taille du contrôleur de vue (définie comme forme libre, plus longue que l'affichage réel, pour contenir toutes mes sous-vues) et enfin cela a fonctionné à nouveau!


Vous êtes les bienvenus! Je sais exactement ce que tu as ressenti .. ;-)
Michele Dall'Agata

Thaaaaks, j'ai passé beaucoup d'heures et cela a résolu mon problème
Andoni Da Silva

3

si vous recevez un message (IOS8 / swift) qui viewDidLayoutSubviewsn'existe pas, utilisez plutôt ce qui suit

override func viewDidAppear(animated: Bool)

Cela l'a corrigé pour moi


2

Quelque chose qui n'a pas été mentionné auparavant!

Assurez-vous que votre prise était correctement connectée au scrollView! Il devrait avoir un cercle rempli, mais même si vous avez rempli le cercle, scrollView n'est peut-être pas connecté - alors vérifiez! Survolez le cercle et voyez si la vue de défilement réelle est mise en évidence! (C'était un cas pour moi)

//Connect below well to the scrollView in the storyBoard
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;

2

La plupart du temps, le code est correct si vous avez suivi un tutoriel, mais ce que de nombreux débutants ne savent pas, c'est que le scrollView ne va PAS faire défiler normalement le simulateur. Il est supposé faire défiler uniquement lorsque vous appuyez sur le tapis de souris et faites défiler simultanément. De nombreux utilisateurs expérimentés de XCode / Swift / Obj-C sont tellement habitués à faire cela et ne savent donc pas comment cela pourrait être ignoré par les débutants. Ciao :-)

@IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(scrollView)
    // Do any additional setup after the view
}

override func viewWillLayoutSubviews(){
    super.viewWillLayoutSubviews()
    scrollView.contentSize = CGSize(width: 375, height: 800)
}

Ce code fonctionnera parfaitement bien tant que vous faites ce que j'ai dit ci-dessus


1

Si aucune des autres solutions ne fonctionne pour vous, vérifiez que votre vue de défilement est bien une UIScrollView dans Interface Builder.

À un moment donné au cours des derniers jours, mon UIScrollView type a spontanément changé en a UIView, même si sa classe a dit UIScrollViewdans l'inspecteur. J'utilise Xcode 5.1 (5B130a).

Vous pouvez soit créer une nouvelle vue de défilement et copier les mesures, les paramètres et les contraintes de l'ancienne vue, soit changer manuellement votre vue en a UIScrollViewdans le xibfichier. J'ai fait une comparaison et j'ai trouvé les différences suivantes:

Original:

<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" directionalLockEnabled="YES" bounces="NO" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wsk-WB-LMH">
...
</scrollView>

Après que le type a changé spontanément:

<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" customClass="UIScrollView" id="qRn-TP-cXd">
...
</view>

J'ai donc remplacé la <view>ligne par ma <scrollView>ligne d' origine .

J'ai également remplacé la balise de fermeture de la vue </view>par </scrollView>.

Assurez-vous de garder l'identifiant identique à la vue actuelle, dans ce cas: id = "qRn-TP-cXd".

J'ai également dû vider le xib du cache de Xcode en supprimant les données dérivées de l'application:

  • Xcode->Window->Organizer->Projects, choisissez votre projet, sur la ligne Données dérivées, cliquez sur Supprimer ...

Ou si vous utilisez un appareil:

  • Xcode->Window->Organizer->Device, choisissez votre appareil-> Applications, choisissez votre application, cliquez sur (-)

Nettoyez maintenant le projet et supprimez l'application du simulateur / de l'appareil:

  • Xcode->Product->Clean
  • iOS Simulator/device->presset maintenez le app->click(X) pour le supprimer

Vous devriez alors pouvoir créer et exécuter votre application et avoir à nouveau la fonctionnalité de défilement.

PS Je n'ai pas eu à définir la taille du contenu de la vue de défilement viewDidLayoutSubviewsou à désactiver la mise en page automatique, mais YMMV.


1

Si votre scrollViewest une sous-vue d'un containerViewcertain type, assurez-vous que votre scrollViewest dans le cadre ou les limites du containerView. J'avais containerView.clipsToBounds = NOce qui me permettait toujours de voir le scrollView, mais parce qu'il scrollViewn'était pas dans les limites de containerViewcelui-ci, je ne détecterais pas les événements tactiles.

Par exemple:

containerView.frame = CGRectMake(0, 0, 200, 200);
scrollView.frame = CGRectMake(0, 200, 200, 200);
[containerView addSubview:scrollView];
scrollView.userInteractionEnabled = YES;

Vous pourrez voir le scrollView mais il ne recevra pas d'interactions utilisateur.


1

l'ajout du code suivant a viewDidLayoutSubviewsfonctionné pour moi avec Autolayout. Après avoir essayé toutes les réponses:

- (void)viewDidLayoutSubviews
{
    self.activationScrollView.contentSize = CGSizeMake(IPHONE_SCREEN_WIDTH, 620);

}

//set the height of content size as required

1

Ajoutez UIScrollViewDelegateet ajoutez le code suivant à la viewDidAppearméthode corrigée pour moi.

@interface testScrollViewController () <UIScrollViewDelegate>

-(void)viewDidAppear:(BOOL)animated {
    self.scrollView.delegate = self;
    self.scrollView.scrollEnabled = YES;
    self.scrollView.contentSize = CGSizeMake(375, 800);
}

1

Mon problème a été résolu par:

  1. définition du contentSize sur le scrollView à une grande hauteur
  2. MAIS aussi j'ai dû corriger les contraintes de haut et / ou de bas sur les vues dans le scrollView, ce qui signifiait que les indicateurs de défilement étaient affichés à l'écran mais que le contenu ne défilait pas

Une fois que j'ai supprimé les contraintes de haut et / ou de bas liées à la zone de sécurité et / ou à la supervision, les vues à l'intérieur du scrollView pouvaient à nouveau défiler et ne restaient pas fixées en haut ou en bas de l'écran!

J'espère que cela arrête quelqu'un d'autre des heures de douleur avec ce problème particulier.


1

encore un autre cas amusant:

scrollview.superview.userInteractionEnabled doit être true

J'ai perdu plus de 2 heures à courir après cela juste pour comprendre que le parent est UIImageView qui, naturellement, a userInteractionEnabled == false


0

Après avoir échoué avec les réponses fournies dans ce fil, je suis tombé sur cet article avec la solution.

Il y a deux choses qui ne sont pas intuitives dans la configuration de la vue de défilement avec mise en page automatique:

  1. Les contraintes que vous définissez comme marge entre la vue de contenu et la vue de défilement n'influencent pas la taille de la vue de contenu. Ce sont vraiment des marges. Et pour que cela fonctionne, la vue de contenu doit avoir une taille fixe.
  2. L'astuce pour la taille fixe est que vous pouvez définir la largeur de la vue de contenu égale à celle du parent de la vue de défilement. Sélectionnez simplement les deux vues dans l'arborescence de gauche et ajoutez la contrainte d'égalité de largeur.

C'est l'essentiel de cet article. Pour une explication complète, y compris des illustrations, consultez-le.


@PredragManojlovic Comment peut-il être plus général que cela? C'est la seule façon dont je pourrais obtenir le scrollview pour fonctionner correctement, en utilisant la mise en page automatique.
H. de Jonge

0

J'ai trouvé qu'avec ce problème de mise en page automatique ... si je fais juste l' ViewControllerutilisation UIViewau lieu de UIScrollViewpour la classe ... alors ajoutez simplement un UIScrollViewmoi - même ... que cela fonctionne.


0

J'ai eu le même problème à IB.

Après avoir défini le début, la fin, le haut et le bas de scrollView sur sa superView. J'ai apporté les modifications suivantes pour rendre le containerView scrollable, ce qui a fonctionné.

Pour que scrollView ne défile que dans le sens horizontal, effectuez la contrainte avec le centre de scrollView Y = le centre de ContainerView Y

et pour le faire défiler verticalement, faites centerX de scrollView = centerX de ContainerView

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.