web-dev-qa-db-fra.com

Comment peupler UITableView de bas en haut?

est-il possible d'inverser l'ordre d'un tableView. J'ai beaucoup cherché une solution, mais tous les résultats n'ont pas tout à fait été une solution à ce que j'essaie de réaliser. Ils suggèrent tous de faire défiler jusqu'à la dernière position d'une table avec scrollToRowAtIndexPath et de renseigner les données à l'envers. Mais cela ne fonctionne pas si le contenu de la table est dynamique et que, dans certains cas, toutes les cellules ne disposent pas de données. Par exemple, dans un tableau normal, l'ordre est le suivant:


étiquette 1

étiquette 2

étiquette 3

vide

vide

direction de défilement
v
V


le résultat souhaité serait:
direction de défilement
^
^

vide

vide

vide

étiquette 3

étiquette 2

étiquette 1


dans cet exemple, si j’utilisais la méthode suggérée scrollToRowAtIndexPath et que j’utilisais la longueur du tableau d’objets, je n’obtiendrais que la troisième cellule par le haut. Et se retrouver avec quelque chose comme ça: 


résultat indésirable:

étiquette 3

étiquette 2

étiquette 1

vide

vide

direction de défilement
v
V


toute aide serait super merci.

26
kai Taylor

Pour remplir le tableau depuis le bas utilisez ceci:

- (void)updateTableContentInset {
    NSInteger numRows = [self tableView:self.tableView numberOfRowsInSection:0];
    CGFloat contentInsetTop = self.tableView.bounds.size.height;
    for (NSInteger i = 0; i < numRows; i++) {
        contentInsetTop -= [self tableView:self.tableView heightForRowAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
        if (contentInsetTop <= 0) {
            contentInsetTop = 0;
            break;
        }
    }
    self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0);
}

Pour inverser l'ordre des éléments, utilisez ceci:

dataSourceArray = dataSourceArray.reverseObjectEnumerator.allObjects;

Swift 2.2 version ( mise à jour ):

func updateTableContentInset() {
    let numRows = tableView(self.tableView, numberOfRowsInSection: 0)
    var contentInsetTop = self.tableView.bounds.size.height
    for i in 0..<numRows {
        let rowRect = self.tableView.rectForRowAtIndexPath(NSIndexPath(forItem: i, inSection: 0))
        contentInsetTop -= rowRect.size.height
        if contentInsetTop <= 0 {
            contentInsetTop = 0
        }
    }
    self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)
}

Swift 3.0 +/4.0 version ( mise à jour ):

func updateTableContentInset() {
    let numRows = tableView(self.tableView, numberOfRowsInSection: 0)
    var contentInsetTop = self.tableView.bounds.size.height
    for i in 0..<numRows {
        let rowRect = self.tableView.rectForRow(at: IndexPath(item: i, section: 0))
        contentInsetTop -= rowRect.size.height
        if contentInsetTop <= 0 {
            contentInsetTop = 0
        }
    }
    self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)
}
24
KlimczakM

premier inverse uitableview 

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

puis inverser cellule dans cellule créer.

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

    ...

    cell.contentView.transform = CGAffineTransformMakeScale (1,-1);
6
waynett

Voici une solution raffinée de la solution de KlimczakM qui fonctionne avec les cellules tableview autolayouted (ainsi que les cellules fixes). Cette solution fonctionne également avec les sections, les en-têtes et les pieds de section.

Swift 3.0 :

func updateTableContentInset(forTableView tv: UITableView) {
    let numSections = tv.numberOfSections
    var contentInsetTop = tv.bounds.size.height -
        (self.navigationBar?.frame.size.height ?? 0)

    for section in 0..<numSections {
        let numRows = tv.numberOfRows(inSection: section)
        let sectionHeaderHeight = tv.rectForHeader(inSection: section).size.height
        let sectionFooterHeight = tv.rectForFooter(inSection: section).size.height
        contentInsetTop -= sectionHeaderHeight + sectionFooterHeight
        for i in 0..<numRows {
            let rowHeight = tv.rectForRow(at: IndexPath(item: i, section: section)).size.height
            contentInsetTop -= rowHeight
            if contentInsetTop <= 0 {
                contentInsetTop = 0
                break
            }
        }
        // Break outer loop as well if contentInsetTop == 0
        if contentInsetTop == 0 {
            break
        }
    }
    tv.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)
}

REMARQUE:

Le code ci-dessus n’a pas été testé, mais devrait fonctionner ......... Assurez-vous simplement que vous faites face à la hauteur de toute barre de navigation ou de tabulation et tout ira bien. Dans le code ci-dessus, je ne le fais que pour la barre de navigation!

3
Alexander W

Le moyen le plus simple est d'utiliser comme UILabel plusieurs lignes + autolayout .-> UITableView devrait redimensionner la base en fonction de son contenu (mise en page intrinsèque) . Créez votre vue table et définissez la classe de base comme suit:

class IntrinsicTableView: UITableView {

override var contentSize:CGSize {
    didSet {
        self.invalidateIntrinsicContentSize()
    }
}

override var intrinsicContentSize: CGSize {
    self.layoutIfNeeded()
    return CGSize(width: UIViewNoIntrinsicMetric, height: contentSize.height)
}

}

Définissez maintenant les contraintes de présentation gauche, droite et inférieure pour votre broche tableview sur la vue parente .. Le plus important est que la contrainte de présentation en haut soit définie sur une valeur supérieure ou égale à 0. Cette table, dont la condition est garantie, ne sera pas plus grande que la vue parent. 

2
Trung Phan

Swift 3.01 - Une autre solution peut être, faire pivoter et retourner la tableView.

self.tableView.transform = CGAffineTransform.init(rotationAngle: (-(CGFloat)(M_PI)))
self.tableView.transform = CGAffineTransform.init(translationX: -view.frame.width, y: view.frame.height)

Lignes d'ancrage UITableView jusqu'en bas

1
Maximo Lucosi

Ne vous donnez pas la peine d'écrire le code vous-même… .. Pourquoi n'utilisez-vous pas ReverseExtension? C'est très facile et vous donnera tous les résultats requis. Veuillez suivre cette url https://github.com/marty-suzuki/ReverseExtension

Remarque: Chaque fois que vous devez ajouter une nouvelle cellule, veuillez insérer le modèle ajouté récemment à l'index zérot du tableau de la source de données. Ainsi, la nouvelle cellule doit s'ajouter en bas. Sinon, cela ajouterait la cellule en haut et vous perdriez la confusion.

1

J'ai fait dans la méthode cellForRowAt:

let reverseIndex = myArray.count-indexPath.row-1

let currCellData = myArray.object(at: reverseIndex) 

et puis vous continuez à travailler avec currCellData

0
Gulz

Cette solution ajuste l’encart de contenu lorsque la taille du contenu change avec KVO. Il prend également en compte le contenu inséré lors du défilement vers le haut, car le défilement vers CGPointZero défilera en haut du contenu au lieu de défiler en haut du tableau.

-(void)startObservingContentSizeChanges
{
    [self.tableView addObserver:self forKeyPath:kKeyPathContentSize options:0 context:nil];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if([keyPath isEqualToString:kKeyPathContentSize] && object == self.tableView)
    {
        // difference between content and table heights. +1 accounts for last row separator
        CGFloat height = MAX(self.tableView.frame.size.height - self.tableView.contentSize.height, 0) + 1;

        self.tableView.contentInset = UIEdgeInsetsMake(height, 0, 0, 0);

        // "scroll" to top taking inset into account
        [self.tableView setContentOffset:CGPointMake(0, -height) animated:NO];

    }
}
0
Eran Goldin