Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView add new rows to bottom with animation without reloading entire table

I have a UITableView and I want to be able to add new rows to the bottom with animation, I was using tableView reloadData and that was working alright, but I want animation. So I switched over too tableView reloadSections but the problem is if I have say 7 rows visible it animates all 7 of those rows. I only want it to animate adding the new row, and not every row on the screen as if it was being added.

Any idea of how to do this?

like image 385
Steven Avatar asked Dec 03 '14 01:12

Steven


1 Answers

Under UITableView you can call a method

- (void) insertRowsAtIndexPaths:(NSArray*) indexPaths
              withRowAnimation: (UITableViewRowAnimation) animation

This allows you to specify the rows in section were you would like to insert a new cell and pass what animation you would like to use. Example code:

//
//  InsertingNewRowToBottomOfTableViewController.m
//  Testing-Code-Snippets
//

#import "InsertingNewRowToBottomOfTableViewController.h"

@interface InsertingNewRowToBottomOfTableViewController ()
@end

#define kTestResuseCellIdentifier @"kTestResuseCell"

@implementation InsertingNewRowToBottomOfTableViewController
{
    NSMutableArray *testArray;
}

- (void) viewDidLoad
{
    [super viewDidLoad];
    self->testArray = [[NSMutableArray alloc] initWithArray:@[@"Test 1", @"Test 2", @"Test 3"]];

    UIRefreshControl *customRefreshControl = [[UIRefreshControl alloc] init];
    customRefreshControl.backgroundColor = [UIColor purpleColor];
    [customRefreshControl addTarget:self action:@selector(onRefresh:) forControlEvents:UIControlEventValueChanged];
    self.refreshControl = customRefreshControl;
}

- (void) didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

- (void) onRefresh: (UIRefreshControl*) refreshControl
{
    [refreshControl endRefreshing];
    [self->testArray addObject:[NSString stringWithFormat:@"Test %lu", self->testArray.count + 1]];
    [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self->testArray.count - 1 inSection:0]] withRowAnimation:UITableViewRowAnimationLeft];
    NSLog(@"Added a new cell to the bottom!");
}

#pragma mark - Table view data source

- (NSInteger) numberOfSectionsInTableView: (UITableView*) tableView
{
    return 1;
}

- (NSInteger) tableView: (UITableView*) tableView numberOfRowsInSection: (NSInteger) section
{
    return self->testArray.count;
}


- (UITableViewCell*) tableView: (UITableView*) tableView cellForRowAtIndexPath: (NSIndexPath*) indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kTestResuseCellIdentifier forIndexPath:indexPath];
    cell.textLabel.text = [self->testArray objectAtIndex:indexPath.row];
    return cell;
}
@end

Update: Swift 3 Version

import UIKit

class InsertingNewRowToBottomOfTableViewController: UITableViewController
{
    private let testResuseCellIdentifier:String = "kTestResuseCell"
    private let testArray:NSMutableArray = NSMutableArray(array:["Test 1", "Test 2", "Test 3"])

    // MARK: - View Events

    override func viewDidLoad()
    {
        super.viewDidLoad()

        let refreshControl:UIRefreshControl = UIRefreshControl()
        refreshControl.backgroundColor = UIColor.purple
        refreshControl.addTarget(self, action:#selector(self.onRefresh(refreshControl:)), for:.valueChanged)
        self.refreshControl = refreshControl
    }

    override func didReceiveMemoryWarning()
    {
        super.didReceiveMemoryWarning()
    }

    // MARK: - UIRefreshControl

    @objc private func onRefresh(refreshControl: UIRefreshControl)
    {
        refreshControl.endRefreshing()
        testArray.add("Test \(self.testArray.count + 1)")

        let indexPath:IndexPath = IndexPath(row:(self.testArray.count - 1), section:0)
        self.tableView.insertRows(at:[indexPath], with: .left)
        NSLog("Added a new cell to the bottom!")
    }

    // MARK: - UITableViewDataSource

    override func numberOfSections(in tableView: UITableView) -> Int
    {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return self.testArray.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier:testResuseCellIdentifier)!
        cell.textLabel?.text = self.testArray.object(at: indexPath.row) as? String
        return cell
    }
}
like image 112
SierraMike Avatar answered Nov 10 '22 01:11

SierraMike