I have a UITableView that loads certain data from a remote feed, and I want to manually add one row on top the table, at the beginning of all the rows loaded from the feed.
So for example, if from the feed I would have a table with the rows
//////////////////////////////////////////
1 (loaded from UITableView data source)
//////////////////////////////////////////
2 (loaded from UITableView data source)
//////////////////////////////////////////
3 (loaded from UITableView data source)
//////////////////////////////////////////
I would like to manually add one row on top of those, so I would have:
//////////////////////////////////////////
0 (manually added)
//////////////////////////////////////////
1 (loaded from UITableView data source)
//////////////////////////////////////////
2 (loaded from UITableView data source)
//////////////////////////////////////////
3 (loaded from UITableView data source)
//////////////////////////////////////////
Is this possible? Is there any other way of doing this in case it is not possible? Like having two UITableView and putting them together or something like that.
Thanks a lot in advance!
Yes it's possible.
In the function where you want to add you row, do :
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:0 inSection:0]];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
you can change the row insertion animation depending of what effect you want.
/!\ your data source and your function tableView:cellForRowAtIndexPath: must be consistent with what you want to display
Add the new element to the array where you have the data, for example:
//This is your data:
NSMutableArray *myData;
//Add new row at the beggining:
[myData insertObject:newData atIndex:0];
//Reload your table view
[self.myTableView reloadData];
If it's static first row you want to add, I would suggest you use a UITableViewHeader to display it instead of UITableViewCell. If you do want to it to be a sell, why don't you add another section? The first section will contain just this one cell, and the second will contain all the cells displaying the data you get from the feed. You can skip the header view, so it will not be noticeable that you have 2 sections instead of one.
Another way is of course to add the data you want to display in the first cell to your datasource and have just one section, but I like the first approach better, because there the code and logic is cleaner
It may useful to you..
1) Insert first that new element into your datasource array.
2) Get visible row indexPath by
NSArray *visibleIndexes = [self.tableview indexPathsForVisibleRows];
3) Then reload all visible rows without animation :
[self.tableview reloadRowsAtIndexPaths:visibleIndexes withRowAnimation:UITableViewRowAnimationNone]
You must be using array to load the data from remote in your table view.
Just push a element(whatever data you need in first row) in beginning of those arrays.
Insert an element in the beginning of array as:
NSMutableArray* array;
[array insertObject:dataInFirstRow atIndex:0];
Related
I have a UITableView of custom cells. Each cell has an NSTimer that can be set by the user and started by tapping a button. The timers work except when a new cell is added to the TableView. In the unwind method (coming from creating a new object for a new cell) I have to reload the data in the TableView so that the new cell appears. This however reloads all the cells causing any running timer to restart. Is there a way I can add the cell without restarting the running timers?
EDIT:
I have a ViewController that creates a new object and then back in the FirstViewController.m I have an unwind method that should update the tableView with a row for the new object. Using the reloadData method won't work because it reloads all of the cells. I would like to just add a new cell without reloading the entire tableView.
-(IBAction)unwind:(UIStoryboardSegue *)segue {
ABCAddItemViewController *source = [segue sourceViewController];
ABCItem *item = source.object;
if (item != nil) {
[self.objectArray addObject:item];
[self.tableView reloadData];
}
}
To do this I've tried adding these lines instead of [self.tableView reloadData]:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[self.objectArray indexOfObject:item] inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
However, the app crashes and I get this message:
'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
The number of rows in the tableView is determined by [self.objectArray count] in the numberOfRowsInSection: method.
It is not a good idea to add timers to cells because they are reused. They are views. My recommendation is to create some objects which have the text / info you want to display in these UITableViewCells and add the timers to those objects. This way the timer info is not stored in the cells and they will store state
There is no need to reload entire table for just inserting one cell. You can add the cell like
self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:row inSection:section]] withRowAnimation:UITableViewRowAnimationLeft];
[self.tableView endUpdates];
Let's say I have a UICollectionView that displaying array of UIImages and the user can select multiple images. So my question is how can I reload the UICollectionView to let it shows only the selected indices without generating a new array that contains the selected UIImages (indices).
First of all you need to Get the images selected with value in array and then use that array as DS and use
[self.collectionView reloadData];
Individual sections and items can also be reloaded:
[self.myCollectionView reloadSections:indexSet];
[self.myCollectionView reloadItemsAtIndexPaths:arrayOfIndexPaths];
I would use an array of ImageObject which contains an UIImage and a BOOL isDisplay for each item. So we don't have to use an another array but a check the variable isDisplay for the "cellForRow".
I'm developing an iOS 5.0+ app with latest SDK.
I have a NSArray with 20 elements. I want to show these 20 elements dynamically on a UITableView. I have disabled scroll on the tableview, and I want to remove the first NSArray element every 1 minute, and then reload UITableView to don't show the element that I have removed and show the remanning ones. And I want to do it with animation.
Searching over internet I have found some examples about how to do it using sections, but I have only one section on the UITableView.
In a nutshel,
Load 20 elements into a NSArray.
Show these 20 elements on an UITableView with scroll disabled.
For loop to remove first NSArray element every minute.
After remove, do UITableView reload with animation.
How can I do that?
You don't have to reload the entire table. Just remove the object from your array (once a minute or whatever). The object that you remove will be at index XXX in your array. And then call :
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:XXX inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
Hope this helps. Cheers!
You need to use this :
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:intvalue(your indexPath) inSection:0];
NSArray *array = [NSArray arrayWithObject:indexPath];
[yourtableview deleteRowsAtIndexPaths:array withRowAnimation:UITableViewRowAnimationFade];
Something weird is going on with my tableview when changing data. I have something like this:
// fadeout existing data
... // change data (new values for the cells are blank)
for{ // loop all rows
[TableView reloadRowsAtIndexPaths: withRowAnimation:]; // smooth fade out
}
// add one new row to the table
... // change data (just add one new row but leave the cells empty)
[TableView reloadData] // reload all of the data (new row should be added)
... // change data (just add values to the existing cells)
for{ // loop all rows
[TableView reloadRowsAtIndexPaths: withRowAnimation:]; // smooth fade in
}
In theory, at least what I think, this should work. But I had some glitches so I added NSLogs in the for loops and in the: - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath so I noticed that my [tableView reloadData] executes after the first row of fade in loop!##
I was thinking about making some kind of a delay between reloadData and fade in loop, but I don't want to force it to work, I want it to work properly.
Is there a better way to accomplish what I'm trying to do?
Can I dynamically add one row at the bottom of the table without calling the 'reloadData' method?
Thanks.
Yes, just use the tableView insertRowsAtIndexPaths method, which will then call your dataSource to load those new rows.
To load a single row at the end of your table, you'd first update your data source to include the new row, then generate the indexpath using:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[yourdata count]-1 inSection:0];
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[tableView insertRowsAtIndexpaths:indexPaths withRowAnimation:whateveryouwant];
Remember, that will immediately call your tableView:cellForRowAtIndexPath method, so update your dataSource to include the extra row before inserting the new row into your table, and be careful that the row index in the indexPath you specify matches the newly added item in your data source.
Ok, I'm stuck. This is an extension of a previous post of mine. Here is what I am trying to do.
I have an Edit button on a navigation bar that when pressed adds a cell at the beginning of my one section table view. The purpose of this cell if to allow the use to add new data to the table; thus it's editing style is Insert. The remaining cells in the table are configured with an editing style of Delete.
Here is my setediting method:
- (IBAction) setEditing:(BOOL)isEditing animated:(BOOL)isAnimated
{
[super setEditing:isEditing animated:isAnimated];
// We have to pass this to tableView to put it into editing mode.
[self.tableView setEditing:isEditing animated:isAnimated];
// When editing is begun, we are adding and "add..." cell at row 0.
// When editing is complete, we need to remove the "add..." cell at row 0.
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
NSArray* path = [NSArray arrayWithObject:indexPath];
// fill paths of insertion rows here
[self.tableView beginUpdates];
if( isEditing )
[self.tableView insertRowsAtIndexPaths:path withRowAnimation:UITableViewRowAnimationBottom];
else
[self.tableView deleteRowsAtIndexPaths:path withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView endUpdates];
// We nee to reload the table so that the existing table items will be properly
// indexed with the addition/removal of the the "add..." cell
[self.tableView reloadData];
}
I am accounting for this extra cell in my code, except I now have two index paths = [0,0] - the new cell and the old original first cell in the table. If I add a call to reload the table view cell in setEditing, the cells are re-indexed, but now my table view is no longer animated.
I want my cake and eat it too. Is there another way to accomplish what I am trying to do and maintain animation?
--John
You can do what you want but you need to keep your data source consistent with the table. In other words, When the table is reloaded, tableView:cellForRowAtIndexPath and the other UITableViewDataSource and UITableViewDelegate methods responsible for building the table should return the same cells depending on editing state that you are adding/removing in setEditing:antimated:.
So, when you insert/delete a cell in setEditing:animated: you need to also make sure your data source reflects the same change. This can be tricky if you are adding a special cell to the beginning of a section but the rest of the data is from an array. One way to do this is while reloading the table, if editing, make row 0 the add cell and use row-1 for your array index for subsequent cells. If you do that you'd also need to add one to tableView:numberOfRowsInSection: to account for the extra cell.
Another way would be to have a section for the add cell and it would have 0 rows when not editing, 1 row otherwise and you return the appropriate cell. This will also require you to configure your table and cell(s) appropriate depending on how you want things to look.