简体   繁体   中英

Load UITableView from the bottom

I'm trying to mimic the iMessage bubble text behaviour with an UITableView . In order to always scroll to the bottom I'm using scrollToRowAtIndexPath when viewDidLoad and viewDidAppear . This is because when the viewDidLoad method is called, the table has not been completely loaded, so I need that extra scroll in viewDidAppear . This code makes the trick. However, what I want is not an animated scroll (setting animated to NO does not solve this), I want the table to be displayed always from the bottom, not load the table and then go to the last row.

Is this possible? I can't find any solution that fits completely with the desired behaviour.

This is the best solution!

Just reverse everything!

tableView.transform = CGAffineTransformMakeRotation(-M_PI);
cell.transform = CGAffineTransformMakeRotation(M_PI);

Swift 4.0:

tableView.transform = CGAffineTransform(rotationAngle: -CGFloat.pi)
cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)

Be careful though, because now the headerView and footerView positions are reversed as well.

You can avoid the call from viewDidLoad because scrolling from within viewDidAppear makes that first call redundant. viewDidAppear is called every time you navigate back to the view but viewDidLoad is only called once when the view is initialized.

I would agree with earlier suggestions of hiding the scroll from the user instead of changing the way a UITableView is loading data. My suggestion would be to use the scrollToRowAtIndexPath method in the viewWillAppear method with animation set to NO. After that if you have to add a new row while the table is visible to the user, use insertRowsAtIndexPaths:withRowAnimation: to add a row at the bottom of the table view. Be sure to take care of adding the data at the end of your data model so that when the user navigates away and comes back, s/he comes back to the same layout.

Hope this helps.

edit: Just saw your reason for not accepting the previous answers and thought I'd elaborate a little more. The solution I propose would require minimum effort, avoid calling reloadData time and again and thus avoid calling the scrollToRowAtIndexPath method again and again. You only need to make one call to scrollToRowAtIndexPath in viewWillAppear to scroll to the bottom of the table view (hiding the transition from the user when doing so) and you wouldn't need to do that again.

I do something similar in an RPN calculator I've built. I have a table view with all the numbers in it and when a number is added to the stack, everything pops up one cell. When I load the view I call:

[self.myTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:NumOfStackItems - 1 inSection:0]
                        atScrollPosition:UITableViewScrollPositionTop animated:NO];

In my viewWillAppear. This way my table view starts shown at the bottom of the stack and no animation is seen. By putting this in the viewWillAppear, every time I navigate to the view, it shows up at the bottom of the table.

When I add numbers to the stack, I just add it in an array that holds all the numbers and then put the text in the proper row like this:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Cell initialization here...
    NSUInteger row_num = [indexPath row];
    cell.rowNumber.text = [NSString stringWithFormat:@"%g", [DataArray objectAtIndex:NumberOfStackItems-row_num-1];// subtract the row number off to get the correct array index
    return cell
}

I also make sure that whenever I update the tableview with a new value i first call the reloadData function, and then call the scrollToRowAtIndexPath function I cited above, this way I stay at the bottom of the table.

The solution is to override viewWillAppear and let it scroll (non-animated) to the bottom:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self goToBottom];
}

-(void)goToBottom
{
    NSIndexPath *lastIndexPath = [self lastIndexPath];
    [self.tableView scrollToRowAtIndexPath:lastIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
}

-(NSIndexPath *)lastIndexPath
{
    NSInteger lastSectionIndex = MAX(0, [self.tableView numberOfSections] - 1);
    NSInteger lastRowIndex = MAX(0, [self.tableView numberOfRowsInSection:lastSectionIndex] - 1);
    return [NSIndexPath indexPathForRow:lastRowIndex inSection:lastSectionIndex];
}

By performing this at viewWillAppear it will be done before the user sees the table.

You can have your UITableView hidden on viewDidLoad , and then change it to visible on viewDidAppear right after you scroll the table to the bottom. This way the user won't see the scrolling animation.

You can fix it by making an invisible footer and do the calculations in there. When the footer is loaded the contentSize is updated. To make it scroll I check set the contentOffset of the tableview.

I have commented out the animation part, since you wanted it without, but it also works.

-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    return 1;
}

-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    if( tableView.contentOffset.y != tableView.contentSize.height - tableView.frame.size.height && automaticScroll ){

        //[UIView animateWithDuration:0.0 animations:^{

            self.contentTableView.contentOffset = CGPointMake(0, tableView.contentSize.height - self.contentTableView.frame.size.height);

        //} completion:^(BOOL finished) {

            [tableView reloadData];

        //}];

        automaticScroll = NO;
    }

    UIView *emptyFooter = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 1)];
    emptyFooter.backgroundColor = [UIColor clearColor];
    return emptyFooter;
}

I created a BOOL automaticScroll to trigger the scroll to the bottom. This should be set in the viewWillAppear method, or whenever you load the data and reload the tableView.

If you want to add rows, you also need to set the BOOL, like:

-(void)addItemButtonClicked:(id)sender
{
    automaticScroll = YES;
    //Add object to data
    [self.contentTableView reloadData];
}

If you need more help, please let me know.

scrollToRowAtIndexPath

用于将tableview中的行滚动到特定位置

just change content inset after load data to move content view of table view if height is less than parent view.

[self.tableView reloadData];         
[self.tableView setContentInset:UIEdgeInsetsMake(self.view.frame.size.height - self.tableView.contentSize.height < 0 ? 0 : self.view.frame.size.height - self.tableView.contentSize.height, 0, 0, 0)];

Swift 3.1

tableView.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)

Credits: @Christos Hadjikyriacou

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM