web-dev-qa-db-fra.com

UIScrollView contentTaille ne fonctionne pas

J'ai mis une UIScrollView dans la view de ma plume et l'ai liée à une propriété IBOutlet.

Maintenant, quand je fais cela dans ma méthode viewDidLoad, cela ne semble avoir aucun effet sur la contentSize:

self.sv.backgroundColor = [UIColor yellowColor]; // this works
CGSize size =  CGSizeMake(1000.0, 1000.0); 
[self.sv setContentSize:size]; // this does not

Il se comporte comme si la contentSize était identique au cadre. Que se passe-t-il? Cela a commencé à fonctionner quand j'ai désactivé AutoLayout. Pourquoi?

54
cannyboy

J'ai eu le même problème. La mise en page automatique pour UIScrollView est fausse.

Solution: mettez tout ce qui se trouve dans UIScrollView dans un autre UIView et placez-le UIView comme enfant unique de UIScrollView. Ensuite, vous pouvez utiliser la mise en page automatique.

Si des éléments proches de la fin sont perturbés (la fin de la direction dans laquelle votre UIScrollView défile), modifiez la contrainte à la fin pour obtenir la priorité la plus basse possible. 

76
yuf

J'ai essayé viewWillLayoutSubviews pour mettre à jour le contentSize de scrollView, cela a fonctionné pour moi.

- (void)viewDidLayoutSubviews
{
  [self.bgScrollView setContentSize:CGSizeMake(320, self.view.frame.size.height* 1.5)];
}

Apple Doc

-(void)viewDidLayoutSubviews

Appelé pour notifier au contrôleur de vue que sa vue vient de définir ses sous-vues.

Discussion

Lorsque les limites changent pour la vue d’un contrôleur de vue, la vue ajuste les positions de ses sous-vues, puis le système appelle cette méthode. Toutefois, cette méthode appelée n’indique pas que les présentations individuelles des sous-vues de la vue ont été ajustées. Chaque sous-vue est responsable de l'ajustement de sa propre disposition.

Votre contrôleur de vue peut remplacer cette méthode pour apporter des modifications après l'affichage des sous-vues par la vue. L'implémentation par défaut de cette méthode ne fait rien.

65
HDdeveloper

La méthode la plus simple et la plus propre consiste à définir contentSize à viewDidAppear afin d’annuler les effets de la mise en pause automatique. Cela n'implique pas l'ajout de vues aléatoires. Cependant, s’appuyer sur l’ordre de chargement pour la mise en œuvre peut ne pas être la meilleure idée.

19
Jlam

Un SUPER moyen simple d'utiliser AutoLayout avec UIScrollViews dans Interface Builder:

Étape 1: Créer une UIScrollView

Étape 2: Créez une UIView qui est un enfant de votre vue de défilement, comme ceci:

-UIScrollView
---UIView
-----Your other content

(Nous appellerons celui-ci contentView).

Étape 3: Dans l'inspecteur de taille, attribuez à cette vue une hauteur et une largeur (par exemple, 320x700).

Étape 4 (avec AutoLayout): Créez des contraintes non ambiguës de votre contentView à son aperçu (la UIScrollView): connectez les 4 arêtes (haut, gauche, dernier et dernier), puis donnez-leur une largeur et une hauteur définies faire défiler aussi. 

Par exemple: si votre vue de défilement couvre tout l'écran, vous pouvez lui donner une largeur de [largeur du périphérique] et une hauteur de 600; il définira ensuite la taille du contenu de la UIScrollView pour correspondre.

OU:

Étape 4 (sans utiliser AutoLayout): Connectez ces deux nouveaux contrôles à votre contrôleur de vue à l'aide de IB (ctrl + glisser de chaque contrôle vers l'application .h @ de votre contrôleur de vue). Supposons que chacune s'appelle scrollView et contentView, respectivement. Ça devrait ressembler à ça:

@interface YourViewController : UIViewController

@property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
@property (strong, nonatomic) IBOutlet UIView *contentView;

@end

Étape 5 (sans utiliser AutoLayout): Dans le fichier .h du contrôleur de la vue, ajoutez (en réalité, remplacez) la méthode suivante:

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    self.scrollView.contentSize = self.contentView.frame.size;
}
14
brandonscript

Ici, nous avons deux problèmes. (1) viewDidLoad est trop tôt; vous devez attendre la fin de la mise en page. (2) Si vous souhaitez utiliser autolayout avec une vue de défilement qui provient d'une nib, vous devez utiliser des contraintes pour décrire complètement la taille de la variable contentSize (et vous ne définissez pas du tout la variable contentSize dans le code), ou si vous voulez le définir en code, vous devez empêcher les contraintes sur les sous-vues de scrollview de dicter la contentSize. On dirait que vous voudriez faire ce dernier. Pour ce faire, vous avez besoin d'un UIView qui agit en tant que sous-vue de niveau supérieur du scrollview. Dans le code, vous devez le définir sur not use autolayout, en activant sa autoresizingMask et en supprimant ses autres contraintes externes. Je montre un exemple de comment faire cela, ici:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch20p573scrollViewAutoLayout/ch20p573scrollViewAutoLayout/ViewController.m

Mais notez également l'exemple suivant, qui montre comment utiliser complètement les contraintes, à la place de contentSize.

13
matt

Utilisez ce code. ScrollView setContentSize doit être appelé asynchrone dans le fil principal.

Rapide:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    DispatchQueue.main.async {
        var contentRect = CGRect.zero

        for view in self.scrollView.subviews {
           contentRect = contentRect.union(view.frame)
        }

        self.scrollView.contentSize = contentRect.size
    }
}

Objectif c:

 - (void)viewDidLayoutSubviews {
     [super viewDidLayoutSubviews];

     dispatch_async(dispatch_get_main_queue(), ^ {
                        CGRect contentRect = CGRectZero;

                        for(UIView *view in scrollView.subviews)
                           contentRect = CGRectUnion(contentRect,view.frame);

                           scrollView.contentSize = contentRect.size;
                       });
}
11
Karen Hovhannisyan

Vous pouvez utiliser ces lignes de code dans votre fichier * .m 

- (void)viewDidLoad{
   [scroll setContentSize:CGSizeMake(320, 800)]   ;
   [scroll setScrollEnabled:TRUE];
   [scroll setShowsVerticalScrollIndicator:NO];
   [scroll setShowsHorizontalScrollIndicator:YES];
}    

pour cela, vous devez intégrer une propriété IBOutlet de UIScrollView dans votre fichier * .h de cette façon:

IBOutlet UIScrollView *scroll;

Et connectez ceci à partir de Storyboard.

Ou,

Vous pouvez utiliser cette méthode dans votre fichier * .m:

-(void)viewDidLayoutSubviews 
{
  [scroll setContentSize:CGSizeMake(320, self.view.frame.size.height* 1.5)];
   // this will pick height automatically from device's height and multiply it with 1.5  
}

Cette solution à la fois fonctionne pour moi dans xcode-5, xcode-6, xcode-6.1, xcode-6.2

5
imti

La définition de contentSize dans viewDidAppear est essentielle. 

Mais j'ai aussi eu une variation de ce qui a fonctionné dans l'écran de 3,5 pouces, et l'écran de 4 pouces. L'écran de 4 pouces a fonctionné, le plus ancien ne fonctionne pas. Les deux iOS 7. Bizarre est un euphémisme!

3
PostCodeism

Si vous utilisez AutoLayout, un moyen très facile de définir la contentSize d'une UIScrollView consiste simplement à ajouter quelque chose comme ceci:

CGFloat contentWidth = YOUR_CONTENT_WIDTH;

NSLayoutConstraint *constraintWidth = 
 [NSLayoutConstraint constraintWithItem:self.scrollView 
                              attribute:NSLayoutAttributeTrailing 
                              relatedBy:NSLayoutRelationEqual 
                                 toItem:self.scrollView 
                              attribute:NSLayoutAttributeLeading 
                             multiplier:1 
                               constant:contentWidth];

[self.scrollView addConstraint:constraintWidth];
1
korovyev

J'avais l'habitude de configurer uiscrollview par programme jusqu'à ce que j'ai regardé le merveilleux tutoriel suivant, étape par étape, pour que uiscrollview et uiview fonctionnent: https://www.youtube.com/watch?v=PgeNPRBrB18

Après avoir regardé la vidéo, vous commencerez à aimer Interface Builder, j'en suis sûr. 

Votez

1
oabarca

Toujours pas de défilement lorsque la hauteur dynamique des étiquettes dépasse la hauteur de la vue.

J'ai fait ce que la réponse de yuf a marqué correct comme indiqué ci-dessus (j'ai ajouté une vue de contenu à ma vue de défilement et défini les contraintes suivantes: largeur de début, de fin, haut et largeur égale de la vue de contenu à la vue de défilement.) pas de défilement lorsque la hauteur des contrôles internes dépasse la hauteur de la vue à défilement.

 enter image description here

Dans ma vue de contenu, j'ai une image et 3 étiquettes en dessous. Chaque étiquette ajuste sa propre hauteur en fonction de la quantité de texte qu'elle contient (elles sont définies sur Word-wrap et sur numberoflines = 0 pour l'obtenir).

Le problème que j'avais était que la hauteur de ma vue de contenu ne s'adaptait pas à la hauteur dynamique des étiquettes lorsqu'elles dépassaient la hauteur de la vue de défilement/vue principale.

Pour résoudre ce problème, j’ai formulé la question et j’ai dû définir la contrainte Bottom Space to Container entre mon étiquette du bas et la contentview et lui donner la valeur 40 (choisie arbitrairement pour lui donner une marge de Nice au bas). Cela signifie maintenant que mon contentview ajuste sa hauteur afin qu'il y ait un espace entre le bas de la dernière étiquette et lui-même et il défile parfaitement!

Yay!

1
Guy Lowe

Je ne pourrais jamais obtenir une mise en page automatique basée sur des contraintes de travail. Puisque ma vue était déjà une sous-classe, UIScrollView, je l’ai résolue en remplaçant setContentView: et en ignorant les mises en page automatiques dont la hauteur est nulle. SetContentSize: message.

@interface MyView : UIScrollView {}
@end

@implementation MyView
- (void)setContentSize:(CGSize)aSize {
    if (aSize.height > 0)
        [super setContentSize:aSize];
}
@end
1
Conor

Essayez ceci ...
ajoute toutes les contraintes comme vous le faites pour UIView(voir la capture d'écran de mon ViewControler dans Storyboard} _)
 enter image description here
Maintenant, le tour commence. sélectionnez votre dernier objet et sélectionnez sa contrainte inférieure. (Voir écran ci-dessus, contrainte inférieure du bouton Instagram (ligne jaune))} et changez l'inspecteur de la taille constante comme dans la capture d'écran ci-dessous.

 enter image description here

j'ai besoin de Constant = 8 mais vous pouvez changer selon vos besoins . cette constante est l'espace entre le bas du bouton orange et le scrollView.

MODIFIER

Assurez-vous de la hiérarchie de votre vue.

0) ViewController.view (facultatif)
1) UIScrollView
2) UIView (renommer "contentView")
3) UIView (cette vue est votre contenu qui fera défiler scrollView)

1
Vats

Autolayout fonctionnait pour les vues de défilement paginées dont les pages occupaient toute la largeur de l'écran. Les pages sont automatiquement redimensionnées en fonction de la taille de la vue de défilement. Je n'ai pas testé cela pour les vues de défilement de largeur inférieure, mais commentez si cela fonctionne - je crois que cela devrait être le cas. Ciblé pour iOS 9, le code écrit dans Swift 2, utilisait un mélange de code IB et de code personnalisé dans awakeFromNib.

Pas:

  • Définir une vue de défilement plein écran.
  • Dans la vue de défilement, ajoutez une UIView (j'ai appelé le mien contentView) dont les bords supérieur, inférieur, inférieur et supérieur sont nuls. la hauteur est égale à celle de la vue de défilement; mais la largeur correspond à la largeur de la vue de défilement multipliée par le nombre de pages. Si vous faites cela visuellement, vous verrez votre vue de contenu s'étendre au-delà de votre vue de défilement dans Inteface Builder.
  • Pour chaque "page" de la contentView, ajoutez des règles Autolayout pour les placer côte à côte, mais surtout, attribuez-leur une contrainte pour que leur largeur soit égale à celle de la vue de défilement et non à celle du contenu.

Exemple de code ci-dessous. embedChildViewController n'est que ma méthode pratique pour ajouter des VCs enfants - regardez plutôt setupLayoutRulesForPages. J'ai exactement deux pages, donc la fonction est trop simple, mais vous pouvez l'élargir à vos besoins.

À mon avis contrôleur:

override func loadView() {
    self.view = self.customView
}

override func viewDidLoad() {
super.viewDidLoad()

self.embedChildViewController(self.addExpenseVC, toView: self.customView.contentView, fillSuperview: false)
self.embedChildViewController(self.addCategoryVC, toView: self.customView.contentView, fillSuperview: false)
self.customView.setupLayoutRulesForPages(self.addExpenseVC.view, secondPage: self.addCategoryVC.view)
}

Ma vue personnalisée:

class __AMVCView: UIView {

    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var contentView: UIView!
    @IBOutlet weak var pageControl: UIPageControl!

    override func awakeFromNib() {
        super.awakeFromNib()

        self.scrollView.pagingEnabled = true
        self.scrollView.bounces = true
        self.scrollView.showsHorizontalScrollIndicator = false
        self.scrollView.showsVerticalScrollIndicator = false

        self.pageControl.numberOfPages = 2

        self.contentView.backgroundColor = UIColor.blueColor()
        self.scrollView.backgroundColor = UIColor.clearColor()
        self.backgroundColor = UIColor.blackColor()
    }

    func setupLayoutRulesForPages(firstPage: UIView, secondPage: UIView) {
        guard self.contentView.subviews.contains(firstPage) && self.contentView.subviews.contains(secondPage)
            else {
                return
        }

        let rules = [
            "H:|-0-[firstPage]-0-[secondPage]-0-|",
            "V:|-0-[firstPage]-0-|",
            "V:|-0-[secondPage]-0-|"
        ]
        let views = [
            "firstPage" : firstPage,
            "secondPage" : secondPage
        ]
        let constraints = NSLayoutConstraint.constraintsWithVisualFormatArray(rules, metrics: nil, views: views)

        UIView.disableAutoresizingMasksInViews(firstPage, secondPage)
        self.addConstraints(constraints)

        // Add the width Autolayout rules to the pages.
        let widthConstraint = NSLayoutConstraint(item: firstPage, attribute: .Width, relatedBy: .Equal, toItem: self.scrollView, attribute: .Width, multiplier: 1, constant: 0)
        self.addConstraint(widthConstraint)
    }

}
0
Matthew Quiros