How to populate UITableView from the bottom upwards?

33,841

Solution 1

To populate UITableView from the bottom:

- (void)updateTableContentInset {
    NSInteger numRows = [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);
}

To reverse the order of elements:

dataSourceArray = dataSourceArray.reverseObjectEnumerator.allObjects;

Swift 4.2/5 version:

func updateTableContentInset() {
    let numRows = self.tableView.numberOfRows(inSection: 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
            break
        }
    }
    self.tableView.contentInset = UIEdgeInsets(top: contentInsetTop,left: 0,bottom: 0,right: 0)
}

Swift 3/4.0 version:

self.tableView.contentInset = UIEdgeInsetsMake(contentInsetTop, 0, 0, 0)

Solution 2

first reverse uitableview

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

then reverse cell in cell create.

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

    ...

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

Solution 3

Swift 4.0 and 4.2 version

First reverse UITableView in viewDidLoad

override func viewDidLoad() {
        super.viewDidLoad()
        tableView.transform = CGAffineTransform(scaleX: 1, y: -1)
}

Then reverse the cell in cellForRowAt.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "MyTableViewCell", for: indexPath) as? MyTableViewCell else { fatalError() }

        cell.contentView.transform = CGAffineTransform(scaleX: 1, y: -1)
        return cell
    }

Solution 4

Here is a refined solution of KlimczakM´s solution that works with autolayouted tableview cells (as well as the fixed ones). This solution also works with sections, section headers and section footers.

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)
}

NOTE:

Above code is untested but should work. Just make sure that you cope for the height of any navbar or tabbar and you'll be fine. In the code above i only do that for the navbar!

Solution 5

Don't bother to write the code by yourself. Why don't you use ReverseExtension. Its very easy and will give you all required results. Please follow this url https://github.com/marty-suzuki/ReverseExtension

Note: Whenever you need to add a new cell, please insert newly added model at zeroth index of datasource array, so new cell should add at bottom. Otherwise it would add the cell at top and you would get confused again.

Share:
33,841
kai Taylor
Author by

kai Taylor

Updated on August 25, 2021

Comments

  • kai Taylor
    kai Taylor over 2 years

    is it possible to reverse the order of a tableView. I have searched a lot for a solution but all the results have not quite been a solution to what I am trying to achieve. They all suggest scrolling to the last position of a table with scrollToRowAtIndexPath and populating the data in reverse. But this doesn't work if the table content is dynamic and in some instances not all the cells have data. For example in a normal tableView the order is:


    label 1

    label 2

    label 3

    empty

    empty

    scroll direction
    v
    V


    the desired result would be:
    scroll direction
    ^
    ^

    empty

    empty

    empty

    label 3

    label 2

    label 1


    in this example if I used the suggested method of scrollToRowAtIndexPath and use the length of the array of objects, I would only get the third cell from the top. And end up with something like this:


    unwanted outcome:

    label 3

    label 2

    label 1

    empty

    empty

    scroll direction
    v
    V


    any help would be great thank you.