Est-il possible de faire un UIScrollView
ajustement automatique à la hauteur (ou à la largeur) du contenu défilant?
Quelque chose comme:
[scrollView setContentSize:(CGSizeMake(320, content.height))];
La meilleure méthode que j'ai jamais rencontrée pour mettre à jour la taille du contenu d'un UIScrollView
en fonction de ses sous-vues contenues:
Objective-C
CGRect contentRect = CGRectZero;
for (UIView *view in self.scrollView.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect.size;
rapide
var contentRect = CGRect.zero
for view in mainScrollView.subviews {
contentRect = contentRect.union(view.frame)
}
mainScrollView.contentSize = contentRect.size
UIScrollView ne connaît pas automatiquement la hauteur de son contenu. Vous devez calculer la hauteur et la largeur pour 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 côte à côte, il vous suffit d’en ajouter la hauteur si vous ne souhaitez pas que le contenu du défilement soit plus grand qu’il ne l’est réellement.
Définissez translatesAutoresizingMaskIntoConstraints
sur NO
sur toutes les vues impliquées.
Positionnez et redimensionnez votre vue de défilement avec des contraintes externes à la vue de défilement.
Utilisez des contraintes pour organiser les vues secondaires dans la vue de défilement, , en vous assurant que les contraintes sont liées aux quatre bords de la vue de défilement et ne reposent pas sur la faites défiler la vue pour obtenir leur taille.
Source: https://developer.Apple.com/library/ios/technotes/tn2154/_index.html
J'ai ajouté ceci à la réponse d'Espuz et de JCC. Il utilise la position y des sous-vues et n'inclut pas les barres de défilement. Edit Utilise le bas de la vue secondaire la plus basse 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;
}
Voici la réponse acceptée dans Swift pour quiconque est trop paresseux pour le convertir :)
var contentRect = CGRectZero
for view in self.scrollView.subviews {
contentRect = CGRectUnion(contentRect, view.frame)
}
self.scrollView.contentSize = contentRect.size
Voici une Swift 3 adaptation de la réponse de @ leviatan:
EXTENSION
import UIKit
extension UIScrollView {
func resizeScrollViewContentSize() {
var contentRect = CGRect.zero
for view in self.subviews {
contentRect = contentRect.union(view.frame)
}
self.contentSize = contentRect.size
}
}
USAGE
scrollView.resizeScrollViewContentSize()
Très facile à utiliser!
L'extension suivante serait utile dans Swift.
extension UIScrollView{
func setContentViewSize(offset:CGFloat = 0.0) {
// dont show scroll indicators
showsHorizontalScrollIndicator = false
showsVerticalScrollIndicator = false
var maxHeight : CGFloat = 0
for view in subviews {
if view.isHidden {
continue
}
let newHeight = view.frame.Origin.y + view.frame.height
if newHeight > maxHeight {
maxHeight = newHeight
}
}
// set content size
contentSize = CGSize(width: contentSize.width, height: maxHeight + offset)
// show scroll indicators
showsHorizontalScrollIndicator = true
showsVerticalScrollIndicator = true
}
}
La logique est la même avec les réponses données. Cependant, il omet les vues masquées dans UIScrollView
et le calcul est effectué après que les indicateurs de défilement ont été masqués.
En outre, il existe un paramètre de fonction facultatif et vous pouvez ajouter une valeur de décalage en transmettant le paramètre à fonction.
La meilleure solution de @leviathan. Il suffit de traduire en Swift en utilisant l’approche FP (programmation fonctionnelle)).
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), {
CGRectUnion($0, $1.frame)
}.size
Vous pouvez obtenir la hauteur du contenu dans UIScrollView en calculant quel enfant "atteint plus loin". Pour calculer cela, vous devez prendre en compte l'origine Y (début) et la hauteur de l'article.
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 ainsi, les éléments (sous-vues) ne doivent pas être empilés directement les uns sous les autres.
Je suis venu avec une autre solution basée sur la solution de @ emenegro
NSInteger maxY = 0;
for (UIView* subview in scrollView.subviews)
{
if (CGRectGetMaxY(subview.frame) > maxY)
{
maxY = CGRectGetMaxY(subview.frame);
}
}
maxY += 10;
[scrollView setContentSize:CGSizeMake(scrollView.frame.size.width, maxY)];
Fondamentalement, nous déterminons quel élément est le plus bas dans la vue et ajoute un remplissage de 10px au bas
Etant donné qu'une scrollView peut avoir d'autres scrollViews ou différentes arborescences de sous-vues inDepth, il est préférable d'effectuer une analyse en profondeur de manière récursive.
Swift 2
extension UIScrollView {
//it will block the mainThread
func recalculateVerticalContentSize_synchronous () {
let unionCalculatedTotalRect = recursiveUnionInDepthFor(self)
self.contentSize = CGRectMake(0, 0, self.frame.width, unionCalculatedTotalRect.height).size;
}
private func recursiveUnionInDepthFor (view: UIView) -> CGRect {
var totalRect = CGRectZero
//calculate recursevly for every subView
for subView in view.subviews {
totalRect = CGRectUnion(totalRect, recursiveUnionInDepthFor(subView))
}
//return the totalCalculated for all in depth subViews.
return CGRectUnion(totalRect, view.frame)
}
}
Utilisation
scrollView.recalculateVerticalContentSize_synchronous()
Ou juste faire:
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
(Cette solution a été ajoutée par moi dans mes commentaires sur cette page. Après 19 votes positifs pour ce commentaire, j'ai décidé d'ajouter cette solution à titre de réponse officielle au profit de la communauté!)
Enveloppant le code de Richy, j'ai créé une classe UIScrollView personnalisée qui automatise complètement le redimensionnement du contenu!
SBScrollView.h
@interface SBScrollView : UIScrollView
@end
SBScrollView.m:
@implementation SBScrollView
- (void) layoutSubviews
{
CGFloat scrollViewHeight = 0.0f;
self.showsHorizontalScrollIndicator = NO;
self.showsVerticalScrollIndicator = NO;
for (UIView* view in self.subviews)
{
if (!view.hidden)
{
CGFloat y = view.frame.Origin.y;
CGFloat h = view.frame.size.height;
if (y + h > scrollViewHeight)
{
scrollViewHeight = h + y;
}
}
}
self.showsHorizontalScrollIndicator = YES;
self.showsVerticalScrollIndicator = YES;
[self setContentSize:(CGSizeMake(self.frame.size.width, scrollViewHeight))];
}
@end
Comment utiliser:
Importez simplement le fichier .h dans votre contrôleur de vue et déclarez une instance de SBScrollView au lieu de celle d’UIScrollView normale.
Pour Swift4 using, réduisez:
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
return $0.union($1.frame)
}).size
Définissez la taille du contenu dynamique comme ceci.
self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);
La taille dépend du contenu chargé à l'intérieur et des options de découpage. Si c'est une vue texte, alors cela dépend aussi du retour à la ligne, du nombre de lignes de texte, de la taille de la police, etc. Presque impossible pour vous de calculer vous-même. La bonne nouvelle est qu’elle est calculée après le chargement de la vue et dans l’apparitionVue. Avant cela, tout est inconnu et la taille du contenu sera identique à celle du cadre. Mais, dans la méthode viewWillAppear et après (tel que viewDidAppear), la taille du contenu sera la taille réelle.
pourquoi pas une seule ligne de code?
_yourScrollView.contentSize = CGSizeMake(0, _lastView.frame.Origin.y + _lastView.frame.size.height);
Je pense que cela peut être un moyen judicieux de mettre à jour la taille d'affichage du contenu de UIScrollView.
extension UIScrollView {
func updateContentViewSize() {
var newHeight: CGFloat = 0
for view in subviews {
let ref = view.frame.Origin.y + view.frame.height
if ref > newHeight {
newHeight = ref
}
}
let oldSize = contentSize
let newSize = CGSize(width: oldSize.width, height: newHeight + 20)
contentSize = newSize
}
}
J'ai aussi trouvé que la réponse de Léviathan fonctionnait le mieux. Cependant, il calculait une hauteur étrange. Lorsque vous parcourez les sous-vues, si l'affichage de défilement est configuré pour afficher des indicateurs de défilement, ceux-ci figureront dans le tableau des sous-vues. Dans ce cas, la solution consiste à désactiver temporairement les indicateurs de défilement avant la mise en boucle, puis à rétablir leur paramètre de visibilité précédent.
-(void)adjustContentSizeToFit
est une méthode publique sur une sous-classe personnalisée de UIScrollView.
-(void)awakeFromNib {
dispatch_async(dispatch_get_main_queue(), ^{
[self adjustContentSizeToFit];
});
}
-(void)adjustContentSizeToFit {
BOOL showsVerticalScrollIndicator = self.showsVerticalScrollIndicator;
BOOL showsHorizontalScrollIndicator = self.showsHorizontalScrollIndicator;
self.showsVerticalScrollIndicator = NO;
self.showsHorizontalScrollIndicator = NO;
CGRect contentRect = CGRectZero;
for (UIView *view in self.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.contentSize = contentRect.size;
self.showsVerticalScrollIndicator = showsVerticalScrollIndicator;
self.showsHorizontalScrollIndicator = showsHorizontalScrollIndicator;
}
cela dépend vraiment du contenu: content.frame.height peut vous donner ce que vous voulez? Cela dépend si le contenu est une seule chose ou une collection de choses.