Thanks in advance. I'm dealing with a single UITableView which is divided into different sections. Users can add or delete cells only from specific sections. The information displayed in the UITableView is stored in an array where each object represents a section:
eg: tableItemsArray = ((arrayForSection1), (arrayForSection2), (arrayForSection3))
I have the animation set up to handle the delete as follows:
[tableView deleteRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationRight];
I then programmatically remove the item from the array to remove it from the data model. However I am having difficulty in how to insert the cell in an animated form.
Currently I am running the current pseudo-algorithm:
Check item isn't anywhere in the array
Add item to array into a specific section
sort this section of the array alphabetically
reload the data
Update
When a new item is added to the array it is stored in a string to keep record of the new item. Once the array has been resorted I iterate through the array of cells to find its indexPath, then I delete the string (to prevent recursive insertion animations) and perform the animation, however the code doesn't animate its insertion into the table. I wondered whether that maybe the animation code (as below) wasn't working as I was using [tableView reloadData]?
// For Each Section in the table:
for (NSMutableArray *object in sectionsInTable) {
// For Each Cell in a section (Cells are stored in an array in index 1)
for (NSString *label in [object objectAtIndex:1]) {
if ([label isEqualToString:_insertedObject]) {
// New item
_insertedObject = Nil;
// animate addition
[self.labelListTableView beginUpdates];
[self.labelListTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:[[object objectAtIndex:1] indexOfObject:label] inSection:[sectionsInTable indexOfObject:object]]] withRowAnimation:UITableViewRowAnimationBottom];
[self.labelListTableView endUpdates];
}
}
}
Any ideas why the animation isn't working?
Thanks
D
Seems that the [tableView reloadData] was preventing the animation.
// Annimate the new Item
// For Each Section in the table:
for (NSMutableArray *object in sectionsInTable) {
// For Each Cell in a section:
for (NSString *cell in [object objectAtIndex:1]) {
if ([cell isEqualToString:_insertedObject]) {
// New item
_insertedObject = Nil;
// animate addition
[tableView beginUpdates];
NSInteger section = [sectionsInTable indexOfObjectIdenticalTo:object];
NSInteger row = [[object objectAtIndex:1] indexOfObjectIdenticalTo:cell];
NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:row inSection:section];
[tableView insertRowsAtIndexPaths: [NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationBottom ];
[tableView endUpdates];
}
}
}
Related
I am trying to follow the following post on reload a cell in a UICollectionView:
UICollectionView update a single cell
I know that I ultimately want something that looks like this:
[self.collectionView reloadItemsAtIndexPaths:??];
But I don't know how to find and pass the indexPath of a particular cell. Can anyone provide any pointers?
I have an NSMutableArray that contains all the cell information (imageViews that are generated in each cell). Ideally, what I'd like to do is pass the index of the NSMutableArray to refresh the corresponding cell on the page. But I'm not sure how the numerical index gets translated into an indexPath.
Thanks in advance for your help!
It depends on your implementation and how you have grouped your cells into sections but let's assume you have one section and each element in your array corresponds to a row in your table.
If you wanted to reload a cell corresponding to an array element at index x all you need to do is write
[_collectionView performBatchUpdates:^{
[_collectionView reloadItemsAtIndexPaths:#[[NSIndexPath x inSection:0]]];
} completion:^(BOOL finished) {}];
Conversely, if you have the cell but want to find its index path you can always call [collectionView indexPathForCell:myCell]
Toy have to pass an array containing the indexPaths that you want to be reloaded.
[self.collectionView reloadItemsAtIndexPaths: indexpathArray];
NSIndexPath has some property names section and row, both represents a cell. If your collection view has single section, you can create a NSIndexPath by setting its section = 0;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:0];
Here rowIndex is your array index. Btw you have to make an array with you newly created indexpaths, then pass it to reloadItemsAtIndexPaths.
Hope this helps.. :)
Obj-C
NSMutableArray *indexPaths = [[NSMutableArray alloc] init]
[indexPaths addObject:indexPath];
[self.collectionView reloadItemsAtIndexPaths: indexPaths];
Swift 4.0
var indexPaths = [IndexPath]()
indexPaths.append(indexPath)
if let collectionView = collectionView {
collectionView.reloadItemsAtIndexPaths(indexPaths)
}
You can use this way for Swift 5.1:
collectionViewOutletName.reloadItems(at: [IndexPath(row: indexNumber, section: sectionNumber)] )
You can use this way for Swift 5:
CollectionView.reloadItems(at: IndexPath])
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *dic = #{#"option":[NSNumber numberWithBool:YES]};
[self.array insertObject:dic atIndex:indexPath.row];
[collectionView reloadItemsAtIndexPaths:#[indexPath]];
}
I am a new IOS Programmer, and i am having a issue.
I have a UITableView with 2 sections, one then is static, and another one is dynamical.
In specific actions i need to add new rows for the second section in runtime..
I know how to manage a UITableView , but not a specific section
Could you help me please?
Best Regards you all
You can use insertRowsAtIndexPaths: method of UITableView
//Update data source with the object that you need to add
[tableDataSource addObject:newObject];
NSInteger row = //specify a row where you need to add new row
NSInteger section = //specify the section where the new row to be added,
//section = 1 here since you need to add row at second section
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationRight];
[self.tableView endUpdates];
You can use the same method insertRowAtIndexPath like
// Add the items into your datasource object first. Other wise you will end up with error
// Manage the number of items in section. Then do
NSIndexPath *indexPath1 = [NSIndexPath indexPathForRow:0 inSection:1];
NSIndexPath *indexPath2 = [NSIndexPath indexPathForRow:1 inSection:1];
[self.tableView insertRowsAtIndexPaths:#[indexPath1,indexPath2] withRowAnimation:UITableViewRowAnimationTop];
This will insert two rows to the section1. Remember before doing this you have manage your datasource object.
Swift 3 version
// Adding new item to your data source
dataSource.append(item)
// Appending new item to table view
yourTableView.beginUpdates()
// Creating indexpath for the new item
let indexPath = IndexPath(row: dataSource.count - 1, section: yourSection)
// Inserting new row, automatic will let iOS to use appropriate animation
yourTableView.insertRows(at: [indexPath], with: .automatic)
yourTableView.endUpdates()
you can do this by using scrolltoinfinite method but before that u have to import 3rd party svpulltorefresh
[self.tableViewMixedFeed addInfiniteScrollingWithActionHandler:^{
CGFloat height = self.tableViewMixedFeed.frame.size.height;
CGFloat contentYoffset = self.tableViewMixedFeed.contentOffset.y;
CGFloat distanceFromBottom = self.tableViewMixedFeed.contentSize.height - contentYoffset;
if(distanceFromBottom<contentYoffSet)
{
[weak insertRowAtBottom];
}
}];
-(void)insertRowAtBottom
{
[self.tableViewMixedFeed beginUpdates];
[self.tableViewMixedFeed insertRowsAtIndexPaths:indexPaths1 withRowAnimation:UITableViewRowAnimationTop];
[self.tableViewMixedFeed endUpdates];
[self.tableViewMixedFeed.infiniteScrollingView stopAnimating];
}
here indexpaths1 is the array of indexpaths of next cells which u want to insert in a table .
try using loop to get the next set of arrays and store them into indexpaths1.
[self.tableView insertRowsAtIndexPaths:#[indexPath1,indexPath2] withRowAnimation:UITableViewRowAnimationTop];
USE THIS METHOD..
I have an app in which I have a UITableview with custom cells and headers. The cells have an inputView so when selected they become first responder and allow the user to input data.
I want to be able to update the visible TableViewCell and header information on the fly while the user is changing it.. easy, just call [tableview reloadData]; ..
Unfortunately this causes the inputview to resign first responder and hide itself.
Is there any way that I can get a reference to the cell itself inside the UITableview so that I can just change the text property? (cellForRow:atIndexPath: returns a new object with the same properties so doesn't work) It seems like the only easy solution may be to store a reference the cells in a dictionary each time a cell is populated, not really the ideal solution.
cellForRowAtIndexPath is literally just
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *orderCell;
static NSString *productCellIdentifier = #"ImageDetailCellIdentifier";
orderCell = [self.tableView dequeueReusableCellWithIdentifier:productCellIdentifier forIndexPath:indexPath];
//set a bunch of properties orderCell.blah
return orderCell;
}
According to UITableView documentation, -cellForRowAtIndexPath: returns an object representing a cell of the table or nil if the cell is not visible or indexPath is out of range.
That is also how I remember it. I don't think your observation is correct that it returns a new object. If the cell is visible you will get hold of it.
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade]; ///as your choice in animation
[tableView endUpdates];
or else
[tableView beginUpdates];
// do some work what ever u need
[tableView endUpdates];
For reloading specific rows, you can use
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
For example,
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:2 inSection:1];
NSArray* indexArray = [NSArray arrayWithObject:indexPath];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
I am using [tableview reloadData]; to reload the data in my UItableView, however when I use this I loose my highlight on my UItableVewCell.
I would like to know the best way to reinstate this highlight.
I set a tempIndexPath when the user selects the cell they edit the information then I call reloadData, then inside cellForRowAtIndexPath I use this code to re-highlight the cell however its not working.
if ([tempIndexPath isEqual:indexPath]) {
cell.selected = YES;
}
This code keeps the highlighted selection, and is safe with resorting/inserts/repositioning since it keeps a reference to the underlying object from the model, instead of the index path. It also scrolls to the selection, which is helpful when the updated model causes the selection to be moved out of the current scroll position's frame.
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Save the selected object at this row for maintaining the highlight later in reloadData
_selectedItem = [_items objectAtIndex:indexPath.row];
}
- (void) reloadData
{
[_itemsTable reloadData];
//Reselect and scroll to selection
int numItems = _items.count;
for (int i = 0; i < numItems; i++) {
NSDictionary *dict = [_numItems objectAtIndex:i];
if (dict == _selectedItem) {
//This is more reliable than calling the indexPathForSelectedRow on the UITableView,
// since the selection is cleared after calling reloadData
NSIndexPath *selectedIndexPath = [NSIndexPath indexPathForRow:i inSection:0];
[_itemsTable scrollToRowAtIndexPath:selectedIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
[_itemsTable selectRowAtIndexPath:selectedIndexPath animated:FALSE scrollPosition:UITableViewScrollPositionNone];
break;
}
}
}
Save the selected row, reload your table view's data and select the row again.
NSIndexPath* selectedIndexPath = [tableView indexPathForSelectedRow];
[tableView reloadData];
[tableView selectRowAtIndexPath:selectedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
You should know that this is dangerous, because if new items were added to the table view before the selected row, the selection will not be the correct cell. You should calculate how many rows were inserted before the row and adjust the selectedIndexPath accordingly.
I have a UISegmentedControl that changes the data in the table view.
[self.mySexyTableView reloadRowsAtIndexPaths:updatedPaths withRowAnimation:UITableViewRowAnimationTop];
Let's say that I display 5 rows for tab one, 2 rows for tab two. When the second tab is clicked the first two rows get new values but the old data from tab one for rows 3 to 5 remains. How can I clear them out ?
Here's a quick sample code to check out: iPhoneCoreDataRecipes
On topic, here is one of the sweetest provided methods:
// If I want to delete the next 3 cells after the one you click
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray* indexPaths = [NSMutableArray array];
for (int i = indexPath.row + 1; i < indexPath.row + 4; i++)
{
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
I ran into this problem, if I understand you properly, that updating doesn't remove cells. So just remove them and then call update. Good luck!