web-dev-qa-db-fra.com

UIScrollView défiler vers le bas par programme

Comment puis-je faire un UIScrollView faire défiler vers le bas dans mon code? Ou d'une manière plus générique, à n'importe quel point d'une sous-vue?

262
nico

Vous pouvez utiliser la fonction setContentOffset:animated: de UIScrollView pour accéder à n’importe quelle partie de la vue Contenu. Voici un code qui défilerait vers le bas, en supposant que votre scrollView est self.scrollView:

CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];

J'espère que cela pourra aider!

585
Ben Gotow

Version rapide de la réponse acceptée pour un collage facile: 

let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height)
scrollView.setContentOffset(bottomOffset, animated: true)
89
Esqarrouth

La solution la plus simple:

[scrollview scrollRectToVisible:CGRectMake(scrollview.contentSize.width - 1,scrollview.contentSize.height - 1, 1, 1) animated:YES];
49
Hai Hw

Juste une amélioration de la réponse existante.

CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];

Il s’occupe également de l’encart du bas (si vous l’utilisez pour ajuster votre vue de défilement lorsque le clavier est visible)

25
vivek241

Régler le contenu du contenu à la hauteur de la taille du contenu est incorrect: cela fait défiler le bas du contenu jusqu'au top de la vue de défilement, et donc hors de vue.

La solution correcte consiste à faire défiler le bas du contenu jusqu'au bottom de la vue de défilement, comme ceci (sv est le UIScrollView):

CGSize csz = sv.contentSize;
CGSize bsz = sv.bounds.size;
if (sv.contentOffset.y + bsz.height > csz.height) {
    [sv setContentOffset:CGPointMake(sv.contentOffset.x, 
                                     csz.height - bsz.height) 
                animated:YES];
}
19
matt

Une solution Swift 2.2, en tenant compte de contentInset

let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)

Cela devrait être dans une extension

extension UIScrollView {

  func scrollToBottom() {
    let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height + contentInset.bottom)
    setContentOffset(bottomOffset, animated: true)
  }
}

Notez que vous voudrez peut-être vérifier si bottomOffset.y > 0 avant de faire défiler

15
onmyway133

Faites défiler vers le haut

- CGPoint topOffset = CGPointMake(0, 0);
- [scrollView setContentOffset:topOffset animated:YES];

Défiler vers le bas

- CGPoint bottomOffset = CGPointMake(0, scrollView.contentSize.height - self.scrollView.bounds.size.height);
 - [scrollView setContentOffset:bottomOffset animated:YES];
13
Waseem

Une implémentation rapide: 

extension UIScrollView {
   func scrollToBottom(animated: Bool) {
     if self.contentSize.height < self.bounds.size.height { return }
     let bottomOffset = CGPoint(x: 0, y: self.contentSize.height - self.bounds.size.height)
     self.setContentOffset(bottomOffset, animated: animated)
  }
}

Vous appelez l'extension comme ceci:

yourScrollview.scrollToBottom(animated: true)
11
duan

Et si contentSize est inférieur à bounds

Pour Swift c'est: 

scrollView.setContentOffset(CGPointMake(0, max(scrollView.contentSize.height - scrollView.bounds.size.height, 0) ), animated: true)
10

J'ai également trouvé un autre moyen utile de le faire dans le cas où vous utilisez une UITableview (qui est une sous-classe de UIScrollView):

[(UITableView *)self.view scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
7
nico

Utilisez la fonction setContentOffset:animated: de UIScrollView pour faire défiler l'écran vers le bas dans Swift.

let bottomOffset : CGPoint = CGPointMake(0, scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
6
Kim

Avec footerView (facultatif) et contentInset, la solution est la suivante:

CGPoint bottomOffset = CGPointMake(0, _tableView.contentSize.height - tableView.frame.size.height + _tableView.contentInset.bottom);
if (bottomOffset.y > 0) [_tableView setContentOffset: bottomOffset animated: YES];
5
Pieter

valdyr, espérons que cela vous aidera:

CGPoint bottomOffset = CGPointMake(0, [textView contentSize].height - textView.frame.size.height);

if (bottomOffset.y > 0)
 [textView setContentOffset: bottomOffset animated: YES];
3
Misha

Catégorie à la rescousse!

Ajoutez ceci à un en-tête d'utilitaire partagé quelque part:

@interface UIScrollView (ScrollToBottom)
- (void)scrollToBottomAnimated:(BOOL)animated;
@end

Et puis à cette implémentation utilitaire:

@implementation UIScrollView(ScrollToBottom)
- (void)scrollToBottomAnimated:(BOOL)animated
{
     CGPoint bottomOffset = CGPointMake(0, self.contentSize.height - self.bounds.size.height);
     [self setContentOffset:bottomOffset animated:animated];
}
@end

Puis implémentez-le où vous voulez, par exemple:

[[myWebView scrollView] scrollToBottomAnimated:YES];
2
BadPirate

Si vous n'avez pas besoin d'animation, cela fonctionne:

[self.scrollView setContentOffset:CGPointMake(0, CGFLOAT_MAX) animated:NO];
1
Krys Jurgowski

Bien que la solution Matt me semble correcte, vous devez également prendre en compte l’encadré de la vue Collection, s’il en existe une qui a été configurée.

Le code adapté sera:

CGSize csz = sv.contentSize;
CGSize bsz = sv.bounds.size;
NSInteger bottomInset = sv.contentInset.bottom;
if (sv.contentOffset.y + bsz.height + bottomInset > csz.height) {
    [sv setContentOffset:CGPointMake(sv.contentOffset.x, 
                                     csz.height - bsz.height + bottomInset) 
                animated:YES];
}
1
tiguero

Pour vous assurer que le fond de votre contenu est visible, utilisez la formule suivante:

contentOffsetY = MIN(0, contentHeight - boundsHeight)

Cela garantit que le bord inférieur de votre contenu est toujours égal ou supérieur au bord inférieur de la vue. MIN(0, ...) est requis car UITableView (et probablement UIScrollView) garantit contentOffsetY >= 0 lorsque l'utilisateur essaie de faire défiler visuellement contentOffsetY = 0. Cela semble assez étrange pour l'utilisateur.

Le code pour implémenter ceci est:

UIScrollView scrollView = ...;
CGSize contentSize = scrollView.contentSize;
CGSize boundsSize = scrollView.bounds.size;
if (contentSize.height > boundsSize.height)
{
    CGPoint contentOffset = scrollView.contentOffset;
    contentOffset.y = contentSize.height - boundsSize.height;
    [scrollView setContentOffset:contentOffset animated:YES];
}
1
jjrscott

Solution pour faire défiler jusqu'au dernier élément d'un tableau 

Swift 3:

if self.items.count > 0 {
        self.tableView.scrollToRow(at:  IndexPath.init(row: self.items.count - 1, section: 0), at: UITableViewScrollPosition.bottom, animated: true)
}
1
MarionFlex

J'ai trouvé que contentSize ne correspond pas vraiment à la taille réelle du texte. Par conséquent, lorsque vous essayez de faire défiler l'écran jusqu'en bas, le texte sera un peu désactivé Le meilleur moyen de déterminer la taille réelle du contenu consiste à utiliser la méthode NSLayoutManager 's usedRectForTextContainer::

UITextView *textView;
CGSize textSize = [textView.layoutManager usedRectForTextContainer:textView.textContainer].size;

Pour déterminer la quantité de texte réellement affichée dans la UITextView, vous pouvez le calculer en soustrayant les encarts du conteneur de texte de la hauteur du cadre.

UITextView *textView;
UIEdgeInsets textInsets = textView.textContainerInset;
CGFloat textViewHeight = textView.frame.size.height - textInsets.top - textInsets.bottom;

Ensuite, il devient facile de faire défiler:

// if you want scroll animation, use contentOffset
UITextView *textView;
textView.contentOffset = CGPointMake(textView.contentOffset.x, textSize - textViewHeight);

// if you don't want scroll animation
CGRect scrollBounds = textView.bounds;
scrollBounds.Origin = CGPointMake(textView.contentOffset.x, textSize - textViewHeight);
textView.bounds = scrollBounds;

Quelques chiffres à titre de référence sur ce que les différentes tailles représentent pour un UITextView vide.

textView.frame.size = (width=246, height=50)
textSize = (width=10, height=16.701999999999998)
textView.contentSize = (width=246, height=33)
textView.textContainerInset = (top=8, left=0, bottom=8, right=0)
0
mikeho
CGFloat yOffset = scrollView.contentOffset.y;

CGFloat height = scrollView.frame.size.height;

CGFloat contentHeight = scrollView.contentSize.height;

CGFloat distance = (contentHeight  - height) - yOffset;

if(distance < 0)
{
    return ;
}

CGPoint offset = scrollView.contentOffset;

offset.y += distance;

[scrollView setContentOffset:offset animated:YES];
0
8suhas

Xamarin.iOS version de la réponse acceptée 

var bottomOffset = new CGPoint (0,
     scrollView.ContentSize.Height - scrollView.Frame.Size.Height
     + scrollView.ContentInset.Bottom);

scrollView.SetContentOffset (bottomOffset, false);
0
Abdur

Il semble que toutes les réponses ne tiennent pas compte de la zone de sécurité. Depuis iOS 11, l'iPhone X dispose d'une zone de sécurité introduite. Cela peut affecter le contentInset du scrollView.

Pour iOS 11 et les versions ultérieures, faites défiler correctement jusqu'au bas avec l'encadré de contenu inclus. Vous devez utiliser adjustedContentInset au lieu de contentInset. Vérifiez ce code:

  • Rapide:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.adjustedContentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
  • Objectif c
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.adjustedContentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
  • Extension rapide (ceci conserve l'original contentOffset.x):
extension UIScrollView {
    func scrollsToBottom(animated: Bool) {
        let bottomOffset = CGPoint(x: contentOffset.x,
                                   y: contentSize.height - bounds.height + adjustedContentInset.bottom)
        setContentOffset(bottomOffset, animated: animated)
    }
}

Références:

0
Honghao Zhang

Xamarin.iOS version pour UICollectionView de la réponse acceptée pour faciliter le copier-coller

var bottomOffset = new CGPoint (0, CollectionView.ContentSize.Height - CollectionView.Frame.Size.Height + CollectionView.ContentInset.Bottom);          
CollectionView.SetContentOffset (bottomOffset, false);
0
Abdur

Cela n'a pas fonctionné pour moi lorsque j'ai essayé de l'utiliser dans UITableViewController sur self.tableView(iOS 4.1), après avoir ajouté footerView. Il fait défiler les frontières, montrant un écran noir.

Solution alternative:

 CGFloat height = self.tableView.contentSize.height; 

 [self.tableView setTableFooterView: myFooterView];
 [self.tableView reloadData];

 CGFloat delta = self.tableView.contentSize.height - height;
 CGPoint offset = [self.tableView contentOffset];
 offset.y += delta;

 [self.tableView setContentOffset: offset animated: YES];
0
valdyr

Pour ScrollView Horizontal

Si vous aimez moi qui a une vue de défilement horizontale et que vous souhaitez faire défiler l'écran jusqu'à la fin (dans mon cas, le plus à droite), vous devez modifier certaines parties de la réponse acceptée:

Objective-C

CGPoint rightOffset = CGPointMake(self.scrollView.contentSize.width - self.scrollView.bounds.size.width + self.scrollView.contentInset.right, 0 );
[self.scrollView setContentOffset:rightOffset animated:YES];

rapide

let rightOffset: CGPoint = CGPoint(x: self.scrollView.contentSize.width - self.scrollView.bounds.size.width + self.scrollView.contentInset.right, y: 0)
self.scrollView.setContentOffset(rightOffset, animated: true)
0
Esmaeil

En rapide:

   if self.mainScroll.contentSize.height > self.mainScroll.bounds.size.height {
        let bottomOffset = CGPointMake(0, self.mainScroll.contentSize.height - self.mainScroll.bounds.size.height);
        self.mainScroll.setContentOffset(bottomOffset, animated: true)
    }
0
Ponja