How to add row/cells dynamically to an UITableView

2020-06-17 05:09发布

Initially i have a table view with only one add button.

when user press this button i need to increment the cells count and add the cells as follows

How to write row count and how to add new rows by click on the add button

//Row count

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{
    return **????** ;
}

// Content on cells/rows

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
       ??????
}

// ### Add New Row.. ###

-(IBAction)myAction:(id)sender
{
    ???????? ;
}

Thanks in advance...

5条回答
放荡不羁爱自由
2楼-- · 2020-06-17 05:40

UITableView has property to insert row or section. see Apple Doc

There are many tutorial on this. there are 2 commonly use to add/delete row/section.

insertRowsAtIndexPaths:withRowAnimation:
deleteRowsAtIndexPaths:withRowAnimation:

I have posted similar answer how to use this : Hiding the table view cells with switch ON/OFF in iPhone

查看更多
狗以群分
3楼-- · 2020-06-17 05:54

In your application You have to add values to Array when you performing action in btn.

For example in your tableview you are displaying NSString in cell.textLABEL.text. These strings are in NSMutableArray.

Now when buttonAction is called

in myAction

{
    NSString *newString =@"NEW CELL";

    [tableArray addObject:newString];
    [tableView reloadData];
}

Try this logic in your application regarding to your modal.

I hope this logic will be helpful to you.

查看更多
放我归山
4楼-- · 2020-06-17 05:58

Reloading of the table view each time you want to add or remove row creates poor experience for the user of your application. Despite the fact it isn’t efficient way to perform this task it also has some negative side effects - selected rows don’t stay selected after reload and change isn’t animated.

UITableView has methods which were created to change content of the table view dynamically. These are:

insertRowsAtIndexPaths:withRowAnimation:
moveRowAtIndexPath:toIndexPath:
deleteRowsAtIndexPaths:withRowAnimation:

Notice that these methods allow you to specify kind of animation which will be used when specified operation is performed - you cannot achieve this kind of behavior when you use reloadData to modify the content of the table view.

Moreover, you can even combine multiple table view operations using additional methods of the table view (this is not necessary):

beginUpdates endUpdates

Just wrap operations you want to perform into calls to beginUpdates and endUpdates methods and table view will create one animation for all operations that have been requested between beginUpdates and endUpdates calls so that whole transition looks nicer that one created by a few separated animations.

[self.tableView beginUpdates]
//calls to insert/move and delete methods   
[self.tableView endUpdates]

It is really important to keep you data source state consistent with the one kept by UITableView. For this reason you must assure that when table view starts to perform requested operations its data source will return correct values.

[self.tableView beginUpdates]
//calls to insert/move and delete methods   
//operations on our data source so that its
//state is consistent with state of the table view
[self.tableView endUpdates]

When table view start performing operations? This depends on whether operations are being in animation block defined by beginUpdates and endUpdates methods. If yes, table view starts to perform operations after endUpdates method call. Otherwise, table view performs operations just after call to insert/move or delete method has been made.

When you are using beginUpdates and endUpdates methods to perform operations on table view you have to know that in this case table view ‚batches’ requested operations and performs them in specific order which is not necessary the same as order of the calls you made on your table view object (Apple's documentation on this topic).

The most important thing to remember is that deletion all operations are always performed before all insertion operations. Also, deletion operations seems to be performed in descending order (operations for indexes 3, 2, 1) when insertion operation are performed in ascending order (operations for indexes 1, 2, 3). Remember about this is crucial in keeping state of your data source consistent with the one kept by table view.

Spend some time on analyzing order of the operations on data source and table view in presented in example below.

Final example:

//initial state of the data source
self.numbers = [@[@(0), @(1), @(2), @(3), @(4), @(5), @(6)] mutableCopy];
//
//...
//

NSArray indexPathsToRemove = @[[NSIndexPath indexPathForRow:3 section:0].
                               [NSIndexPath indexPathForRow:0 section:0];
NSArray indexPathsToAdd = @[[NSIndexPath indexPathForRow:6 section:0],
                            [NSIndexPath indexPathForRow:5 section:0]];

[self.tableView beginUpdates];

[self.numbers removeObjectAtIndex:3];
[self.numbers removeObjectAtIndex:0];

[self.numbers insertObject:@(10) atIndex:4];
[self.numbers insertObject:@(11) atIndex:5];

[self.tableView insertRowsAtIndexPaths:indexPathsToAdd withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView deleteRowsAtIndexPaths:indexPathsToRemove withRowAnimation:UITableViewRowAnimationAutomatic];

[self.tableView endUpdates];
//final state of the data source ('numbers') - 1, 2, 4, 5, 6, 10, 11
查看更多
▲ chillily
5楼-- · 2020-06-17 06:02

You can just add object in array and reload your tableview on button click.

[array addobject:@""];
[tableview reloaddata];
查看更多
淡お忘
6楼-- · 2020-06-17 06:03

There are other correct answers here (which you should read because they go further in-depth), but I struggled for over a week with this after reading all the solutions I could find because there weren't any (that I found!) with comprehensive examples.

Rules for this to work: 1. Changes must be made directly to the array that contains the items you're displaying in the UITableView. If you set some value in a UITableViewCell in the tableView:cellForRowAtIndexPath: method to equal values in self.expandableArray, then changes must also be made to self.expandableArray in order for these methods to work.

  1. changes to the array of items that are displayed in the tableView must be made in-between [tableView beginUpdates] and [tableView endUpdates]
  2. The count of the indexPaths array must equal the count of the additional items you're adding to the tableView (I think that's obvious, but it doesn't hurt to point that out)

here is a very simple example that would work on its own.

    @interface MyTableViewController ()
@property (nonatomic, strong) NSMutableArray *expandableArray;
@property (nonatomic, strong) NSMutableArray *indexPaths;
@property (nonatomic, strong) UITableView *myTableView;
@end

@implementation MyTableViewController

- (void)viewDidLoad
{
    [self setupArray];
}

- (void)setupArray
{
    self.expandableArray = @[@"One", @"Two", @"Three", @"Four", @"Five"].mutableCopy;
}

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

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //here you should create a cell that displays information from self.expandableArray, and return it
}

//call this method if your button/cell/whatever is tapped
- (void)didTapTriggerToChangeTableView
{
    if (/*some condition occurs that makes you want to expand the tableView*/) {
        [self expandArray]
    }else if (/*some other condition occurs that makes you want to retract the tableView*/){
        [self retractArray]
    }
}

//this example adds 1 item
- (void)expandArray
{
    //create an array of indexPaths
    self.indexPaths = [[NSMutableArray alloc] init];
    for (int i = theFirstIndexWhereYouWantToInsertYourAdditionalCells; i < theTotalNumberOfAdditionalCellsToInsert + theFirstIndexWhereYouWantToInsertYourAdditionalCells; i++) {
        [self.indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
    }

    //modify your array AND call insertRowsAtIndexPaths:withRowAnimation: INBETWEEN beginUpdates and endUpdates
    [self.myTableView beginUpdates];
    //HERE IS WHERE YOU NEED TO ALTER self.expandableArray to have the additional/new data values, eg:
    [self.expandableArray addObject:@"Six"];
    [self.myTableView insertRowsAtIndexPaths:self.indexPaths withRowAnimation:(UITableViewRowAnimationFade)];  //or a rowAnimation of your choice

    [self.myTableView endUpdates];
}

//this example removes all but the first 3 items
- (void)retractArray
{
    NSRange range;
    range.location = 3;
    range.length = self.expandableArray.count - 3;

    //modify your array AND call insertRowsAtIndexPaths:withRowAnimation: INBETWEEN beginUpdates and endUpdates
    [self.myTableView beginUpdates];
    [self.expandableArray removeObjectsInRange:range];
    [self.myTableView deleteRowsAtIndexPaths:self.indexPaths withRowAnimation:UITableViewRowAnimationFade];  //or a rowAnimation of your choice
    [self.myTableView endUpdates];
}

@end

I hope this saves someone a lot of time and headache. If you do it this way, you don't need to reload the whole tableView to update it, and you're able to select an animation for it. Free code, don't knock it.

查看更多
登录 后发表回答