Move index path by one in TableView (iOS) - ios

I have a chat application, in which i want to increase the index path by one when new chat data come. But it is not happening through my code I am sharing code with screen shot please help.
NSUInteger messageCount = [self numberOfMessages];
if (self.conversation && messageCount > 0) {
NSLog(#"%ld",(long)indexPathValue.row);
NSIndexPath* ip = [NSIndexPath indexPathForRow:indexPathValue.row + 1 inSection:0];
NSLog(#"%ld",(long)ip.row);
[layerChatTableView scrollToRowAtIndexPath:ip atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

Below code allows you to go last indexpath with scroll position of bottom.
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:messageCoutnt-1 inSection:0] atScrollPosition:UITableViewScrollPositionButtom animated:NO];
Try and let me know

I am assuming that you have handled the datasource updating part and that you are updating the table view on main thread.
You can try to add new row at bottom like this:
NSInteger section = 0;
NSInteger newCount = [self tableView:self.tableView numberOfRowsInSection:section];
NSMutableArray *paths = #[].mutableCopy;
[paths addObject:[NSIndexPath indexPathForRow:newCount inSection:section]];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
You can also add more than 1 row with some modifications.
Hope this helps.

Related

iOS - UITableView Delete All Rows Within A Section

I have a UITableView with expandable sections. When a user goes to another view, I need all the expanded sections to collapse, which I'll need to put in the viewWillDisappear method.
I've found solutions only on how to delete all rows from a table view at once, but is there a way to delete all the rows from a specific section?
EDIT:
I have figured out a solution, but I'm not sure if it's optimal or can lead to inefficiencies in the future. Whenever a cell is expanded, it gets added to an NSMutableIndexSet. So in my viewWillDisappear method, I iterate over the expanded sections like so:
-(void)viewWillDisappear:(BOOL)animated
{
if (expandedSections.count != 0) {
NSLog(#"COLLAPSING CALLED");
[self.tableView beginUpdates];
NSUInteger section = [expandedSections firstIndex];
do
{
NSInteger rows;
NSMutableArray *tmpArray = [NSMutableArray array];
rows = [self tableView:self.tableView numberOfRowsInSection:section];
[expandedSections removeIndex:section];
for (int i=1; i<rows; i++) {
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i inSection:section];
[tmpArray addObject:tmpIndexPath];
}
[self.tableView deleteRowsAtIndexPaths:tmpArray withRowAnimation:UITableViewRowAnimationTop];
NSIndexPath *expandableCellIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:expandableCellIndexPath];
cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[self.colorHolder objectAtIndex:section] type:DTCustomColoredAccessoryTypeRight];
section = [expandedSections indexGreaterThanIndex:section];
} while (section != NSNotFound);
[self.tableView endUpdates];
}
}
Please let me know if this is a good solution or, if I'm suspecting correctly, if this will lead to slower transitions between views in the future when there are more rows in each expanded section. Any help or advice would be appreciated. Thanks.
If you want to animate changes, you will need to first update your data source (to return 0 for number of rows in the section) then remove section and add section at the same index path in one transaction between [tv beginUpdates] [tv endUpdates]
Otherwise just update the data source and reload the table on your way back to the VC (if you don't want any animations)
I did not read this in detail but surely the for loop should start at zero.
for (int i=0; i<rows; i++) {
NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForRow:i inSection:section];
[tmpArray addObject:tmpIndexPath];
}
otherwise you will only delete all but the first cells in the section.

How to postion tableView to the last inserted section SMOOTH

EDIT:
I found this SO thread.
UITableView inserting section at top while scrolling
I have a tableView
I load it with 5 sections initially
Then I scroll up and when section 0 and row 0 is displayed, I load the next 5 sections and insert in table view using
[self beginUpdates];
[self deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
[self insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
[self insertSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationNone];
[self insertSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationNone];
[self endUpdates];
However my problem is the tableView gets position at section 0 and row 0 after the inserts
but I want to position at last row of last new section inserted (which is section 2 in code above)
I tried this both inside and outside begin/end updates
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:2];
[self scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionBottom animated:YES];
But it does it abruptly.
After inserting sections you can also scroll the table view to the intended index path using
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:2];
[UIView animateWithDuration: 1.0
animations: ^{
[tableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionBottom animated:NO];
}
completion: ^(BOOL finished){
}
];
Note:
1) Insert the above code after [self endUpdates];
2) Please ensure that you keep the animated flag to NO using scrollToRowAtIndexPath: atScrollPosition: animated: while you are using it with UIView's animateWithDuration: animations: completion: API.
3) Also you can calculate the duration based on the distance (content size, height wise for vertical scroll), i.e duration can depend on the distance between source index path and destination index path.
Please try below code.
[self beginUpdates];
/*
Insert your sections
*/
[self endUpdates];
[self performSelector:#selector(scroll) withObject:nil afterDelay:0.1];
-(void)scroll
{
if([Your array count] > 0)
{
[YOURTABLENAME scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:2] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
}
I Hope above code is work for you.
Thanks

Unable to remove all UITableView cells with animation

I can's seem to be able to remove all table rows. What seems to happen is that only the cells that are in view are removed and then the ones that were out of view move up. Also checked and my data source contains only the cels that are in view at the time of deletion. Heres the code
NSMutableArray *left = [[NSMutableArray alloc]init];
NSMutableArray *right = [[NSMutableArray alloc]init];
for(int i=0;i<dataSource.count;i++){
[dataSource removeObjectAtIndex:i];
NSIndexPath *ip = [NSIndexPath indexPathForRow:i inSection:0];
if(i%2==0)
[left addObject:ip];
else
[right addObject:ip];
}
[_view.tableView beginUpdates];
[_view.tableView deleteRowsAtIndexPaths:[NSArray arrayWithArray:left]
withRowAnimation:UITableViewRowAnimationLeft];
[_view.tableView deleteRowsAtIndexPaths:[NSArray arrayWithArray:right]
withRowAnimation:UITableViewRowAnimationRight];
[_view.tableView endUpdates];
What happens now is that only the cells in view are removed and the rest pop in after the removal (also the issue seems to pop up since the dataSource only contains the rows that are in view for some reason). What i want is to remove all the rows. Any ideas?
The problem is in the for loop condition. The dataSource.count gets smaller each iteration. Try this:
for(int i=0;i<dataSource.count;i++){
NSIndexPath *ip = [NSIndexPath indexPathForRow:i inSection:0];
if(i%2==0)
[left addObject:ip];
else
[right addObject:ip];
}
[dataSource removeAllObjects];
try something like this:
[_view.tableView beginUpdates];
UITableViewRowAnimation animation;
for(int i = dataSource.count - 1; i>= 0; i--)
{
[dataSource removeObjectAtIndex: i];
NSIndexPath* ip = [NSIndexPath indexPathForRow: i
inSection: 0];
if(i % 2 == 0)
{
animation = UITableViewRowAnimationLeft;
}
else
{
animation = UITableViewRowAnimationRight;
}
[_view.tableView deleteRowsAtIndexPaths: #[ip]]
withRowAnimation: animation];
}
[_view.tableView endUpdates];
You can do this in easy way...
[dataSource removeAllObjects];
[_view.tableView reloadData];
i think that you can put your dataSource = #[]; and [self.tableview reloadData]; and remove all cell in your tableview

Inserting Row at Index path issues

I am creating an iOS app that is set up as a hierarchy of data. I have no issues on the first page adding and deleting objects or even transitioning to the next page. The problem occurs on the second page which is set up exactly like the first. When I press the add button to add an object the program crashes and sends back the error SIGABRT.
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:YES]; << crashes on this line
here is the function add tapped:
- (void)addTapped:(id)sender {
StudentDoc *newDoc = [[[StudentDoc alloc] initWithTitle:#"New Student" rating:0 thumbImage:nil fullImage:nil] autorelease];
[_students addObject:newDoc];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_students.count-1 inSection:0];
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:YES];
[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
}
number of rows in section:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _students.count;
}
I have been under the impression that the count is what is causing the problem, but I have monitored the count and it stays consistent.
Overall I have no idea why it is crashing at this point because the page before it uses the exact same function to add objects on that page. Any ideas?
Normally if you'd messed up your array or row indexes you'd expect an exception to be logged in the console, not a SIGABRT. Have you enabled NSZombies and break-on-exceptions in Xcode? That may help to diagnose the issue.
You should put insert row at index path between begin updates and end updates block.
- (void)addTapped:(id)sender {
StudentDoc *newDoc = [[[StudentDoc alloc] initWithTitle:#"New Student" rating:0 thumbImage:nil fullImage:nil] autorelease];
[_students addObject:newDoc];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_students.count-1 inSection:0];
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:YES];
[self.tableView endUpdates];
[self.tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
}
I've done almost the same, tho I split it into 2 lines:
NSInteger idx = [_students count] - 1;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:idx inSection:0];
I wonder if that would make a difference.
You're adding an object to the data source, but replacing an existing row in the table, not adding one, resulting in one row in the indexPath but 2 items in the data source array.
For instance, if you have one item in _students, you'll have one index path, {0,0}. When you add a row, you're adding it at indexPath {_students.count - 1, 0}, which would be {1 - 1, 0} or {0, 0}. Your data source should match any indexPaths you insert or remove, and in your case you're always ending up with one more item in your data source than you add/remove.
If you always want to add an item, instead of:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_students.count-1 inSection:0];
You want:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_students.count inSection:0];

Add cell/data to the top of UITableView

I'm trying to create a simple chat application for iOS. It currently looks like this:
I want to change the order that the messages is displayed, i.e. display the latest message over the older messages. My current implementation looks like this:
// Datasource for the tableView
messages = [[NSMutableArray alloc] init];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
[...]
// messageTextView is a contentView subView.
messageTextView.text = [messages objectAtIndex:indexPath.row];
[...]
- (IBAction)sendMessage:(id)sender
{
[messages addObject:messageField.text];
messageField.text = #"";
[self.tableView reloadData];
/*
I have tried the implementation below, but I always got an exception.
[self.tableView beginUpdates];
NSIndexPath *path1 = [NSIndexPath indexPathForRow:1 inSection:0];
NSArray * indexArray = [NSArray arrayWithObjects:path1,nil];
[self.tableView insertRowsAtIndexPaths:indexArray
withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
*/
}
Any tips on how to do this would be great.
Thanks.
Simple you need to insert the new UITableViewCell at the 0 index. Also modify your Datasource otherwise your app will crash. Below I show how to modify your UITableView. Modifying your datasource is easy.
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[tableView beginUpdates];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];
What you are essentially doing here is inserting the new chat message cell at the 0th index position. You could use a nice animation effect to make it appear or fade in.
There are various animations that you can use here-
UITableViewRowAnimationBottom
UITableViewRowAnimationFade
UITableViewRowAnimationMiddle
UITableViewRowAnimationNone
UITableViewRowAnimationRight
UITableViewRowAnimationTop
You can try.
[messages insertObject:messageField.text atIndex:0];
instead of [messages addObject:messageField.text];.
Swift Solution
Define array like this
var arrMessage = [AnyObject]()
and Button Action
#IBAction func btnSendMessageTapped(sender: AnyObject) {
arrMessage.insert(txtTypeMessage.text!, atIndex: 0)
txtTypeMessage.text = ""
self.tblMessage.reloadData()
}

Resources