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?
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.
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)];
}
-(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.
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.
É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;
}
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:
Mais notez également l'exemple suivant, qui montre comment utiliser complètement les contraintes, à la place de contentSize
.
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;
});
}
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
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!
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];
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
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.
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!
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
Essayez ceci ...
ajoute toutes les contraintes comme vous le faites pour UIView
(voir la capture d'écran de mon ViewControler dans Storyboard} _)
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.
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)
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:
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.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)
}
}