web-dev-qa-db-fra.com

UITableView, défiler vers le bas sur recharger?

J'ai un UITableView avec cells qui sont mis à jour dynamiquement. Tout fonctionne bien sauf lorsque tableview.reload est appelé (voir ci-dessous) pour actualiser la cells du tableau. J'aimerais que le tableau défile vers le bas pour afficher les nouvelles entrées. 

- (void)reloadTable:(NSNotification *)notification {
    NSLog(@"RELOAD TABLE ...");
    [customTableView reloadData];
    // Scroll to bottom of UITable here ....
}

J'avais prévu d'utiliser scrollToRowAtIndexPath:atScrollPosition:animated: mais j'ai ensuite remarqué que je n'avais pas accès à une indexPath.

Est-ce que quelqu'un sait comment faire cela, ou d'un rappel delegate que je pourrais utiliser?

58
fuzzygoat

Utilisation:

NSIndexPath* ipath = [NSIndexPath indexPathForRow: cells_count-1 inSection: sections_count-1];
[tableView scrollToRowAtIndexPath: ipath atScrollPosition: UITableViewScrollPositionTop animated: YES];

Ou vous pouvez spécifier l'index de section manuellement (Si une section => index = 0).

120
Max

Une autre solution consiste à retourner le tableau verticalement et chaque cellule verticalement:

Appliquez la transformation à UITableView lors de l'initialisation:

tableview.transform = CGAffineTransformMakeScale(1, -1);

et dans cellForRowAtIndexPath:

cell.transform = CGAffineTransformMakeScale(1, -1);

Ainsi, vous n'aurez pas besoin de solutions de contournement pour les problèmes de défilement, mais vous devrez réfléchir un peu plus sur les interactions contentInsets/contentOffsets et en-tête/pied de page.

35
Michael Wilson
-(void)scrollToBottom{

        [self.tableView scrollRectToVisible:CGRectMake(0, self.tableView.contentSize.height - self.tableView.bounds.size.height, self.tableView.bounds.size.width, self.tableView.bounds.size.height) animated:YES];

}
33
mkral
//In Swift 

var iPath = NSIndexPath(forRow: self.tableView.numberOfRowsInSection(0)-1, 
                        inSection: self.tableView.numberOfSections()-1)
self.tableView.scrollToRowAtIndexPath(iPath, 
                                      atScrollPosition: UITableViewScrollPosition.Bottom,                     
                                      animated: true)
9
ytbryan

C'est une autre solution, qui a bien fonctionné dans mon cas, lorsque la hauteur de la cellule est grande. 

- (void)scrollToBottom
{
    CGPoint bottomOffset = CGPointMake(0, _bubbleTable.contentSize.height - _bubbleTable.bounds.size.height);
    if ( bottomOffset.y > 0 ) {
        [_bubbleTable setContentOffset:bottomOffset animated:YES];
    }
}
4
wzbozon

Comme c'est quelque chose que vous voudrez utiliser très souvent, je vous suggère de créer une extension de classe sur UITableView:

extension UITableView {
    func scrollToBottom(animated: Bool = true) {
        let section = self.numberOfSections
        if section > 0 {
            let row = self.numberOfRowsInSection(section - 1)
            if row > 0 {
                self.scrollToRowAtIndexPath(NSIndexPath(forRow: row - 1, inSection: section - 1), atScrollPosition: .Bottom, animated: animated)
            }
        }
    }
}
4
jfgrang

il est préférable de faire l’extension sur UIScrollView au lieu de UITableView, de cette façon cela fonctionne avec scrollView, tableView, collectionView (vertical), UIWebView (vue de défilement interne), etc.

public extension UIScrollView {

    public func scrollToBottom(animated animated: Bool) {
        let rect = CGRectMake(0, contentSize.height - bounds.size.height, bounds.size.width, bounds.size.height)
        scrollRectToVisible(rect, animated: animated)
    }

}
1
aryaxt

Swift 3

Pour tous ceux qui essaient ici de comprendre comment résoudre ce problème, la clé consiste à appeler la méthode .layoutIfNeeded() après .reloadData():

tableView.reloadData()
tableView.layoutIfNeeded()
tableView.setContentOffset(CGPoint(x: 0, y: tableView.contentSize.height - tableView.frame.height), animated: false)

Je travaillais avec plusieurs sections dans UITableView et cela a bien fonctionné.

0
Chris Tsitsaris

C'est la meilleur façon.

- (void)scrollToBottom
{
    CGFloat yOffset = 0;

    if (self.tableView.contentSize.height > self.tableView.bounds.size.height) {
        yOffset = self.tableView.contentSize.height - self.tableView.bounds.size.height;
    }

    [self.tableView setContentOffset:CGPointMake(0, yOffset) animated:NO];
}
0
Jigar Patel

essayez ce code, il peut vous aider:

    self.tableView.reloadData()
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+0.1, execute: {
        let indexPath = IndexPath(row: self.dateSource.count-1, section: 0)
        self.tableView.scrollToRow(at: indexPath, at: UITableViewScrollPosition.bottom, animated: true)
    })
0
muhlenXi

Swift 5

    func scrollToBottom() {
        let section = self.tableView.numberOfSections
        let row = self.tableView.numberOfRows(inSection: self.tableView.numberOfSections - 1) - 1;
        guard (section > 0) && (row > 0) else{ // check bounds
            return
        }
        let indexPath = IndexPath(row: row-1, section: section-1)
        self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
    }

Je ne suis pas d'accord pour dire que nous devrions utiliser cells_count, sections_count, self.dateSource.count et ainsi de suite. Au lieu de cela, le délégué sera meilleur.

0
mistdon

Fot Swift 5

extension UITableView {
    func scrollToBottom(animated: Bool = true) {
        let section = self.numberOfSections
        if section > 0 {
            let row = self.numberOfRows(inSection: section - 1)
            if row > 0 {

                self.scrollToRow(at: IndexPath(row: row-1, section: section-1), at: .bottom, animated: animated)
            }
        }
    }
}
0
pVaskou