IOS- UITableView scroll back to top - ios

i am using Custom UITableView in my project for displaying data it works fine but when i try to scroll it to bottom it doesn't stop at desired cell it always jumps to the top of the table. only shows 2-3 cells.
please suggest what to add to overcome this problem.
i tried so many codes answered in similar type of questions but they doesn't work
i uses the following codes for UITableView
newsFeedTable = [[UITableView alloc]init];
CGFloat Ytablepadding = CGRectGetMaxY(homeView.frame)+60;
CGFloat heighttable = 700;
newsFeedTable.frame = CGRectMake(0,Ytablepadding, self.view.frame.size.width, heighttable);
[self.view addSubview:newsFeedTable];
newsFeedTable.delegate=self;
newsFeedTable.dataSource= self;

Add this code in you viewDidload :
NSIndexPath *myIndexPath = [NSIndexPath indexPathForRow:AddYourLastIndex inSection:0];
[self.tbl_presentation selectRowAtIndexPath:myIndexPath animated:YES scrollPosition:UITableViewScrollPositionBottom];

UITableView is a subclass of UIScrollView, so you can also use:
[newsFeedTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
Or
[newsFeedTable setContentOffset:CGPointZero animated:YES];

Simplest you can do is :
calling [newsFeedTable setContentOffset:CGPointMake(0, CGFLOAT_MAX)]
will do what you want.

You need to adjust the table view's height according to the height of the view, of which you are making subview to see the last row of the table or rather to scroll it to bottom:
newsFeedTable.frame = CGRectMake(0,Ytablepadding, self.view.frame.size.width, self.view.frame.size.height - Ytablepadding);
and to scroll it to last row on table reload/ after popping of data, scroll it programatically like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[newsFeedTable reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
int lastRowNumber = [newsFeedTable numberOfRowsInSection:0] - 1;
NSIndexPath* ip = [NSIndexPath indexPathForRow:lastRowNumber inSection:0];
[newsFeedTable scrollToRowAtIndexPath:ip atScrollPosition:UITableViewScrollPositionTop animated:NO];
});
});
}];

Related

UITabelView scrollToRowAtIndexPath scroll to bottom sometimes will made my table disappear, why?

I want my tableview scroll to the bottom when first time into the view, but sometimes won't scroll to the bottom, and sometimes will made my table disappear. (usually happened when first time or second time).
here's my scrolling code:
-(void)tableScrollToBottom{
[self.tableView reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
NSIndexPath* indexPath = [NSIndexPath indexPathForRow: ([self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1) inSection: ([self.tableView numberOfSections]-1)];
[self.tableView scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionBottom
animated:YES];
});
}
and I also have [self tableScrollToBottom] in viewDidAppear, cause if I only scroll the table in viewDidLoad the table always won't scroll to very bottom, and I don't know why, it's really confusing me.
And I tried to put [self.tableView layoutIfNeeded] in [self tableScrollToBottom], and remove the dispatch_async, it seems like the first time I opened the app and into the view still can't scroll to the very bottom, after the first time, it'll scroll to the bottom correctly, I don't know what's the difference between the first time open the app and into that view and after the first time.(my data get from server and it's from previous, and my tableview row height is dynamic).
here's my code in [self tableScrollToBottom] now:
-(void)tableScrollToBottom {
[self.tableView layoutIfNeeded];
NSIndexPath* indexPath = [NSIndexPath indexPathForRow: ([self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1) inSection: ([self.tableView numberOfSections]-1)];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
and here's where I called [self tableScrollToBottom] :
-(void)getDicData {
for (int i = 0; i < _csDictArr.count; i ++) {
[_chatPersonArray addObject:_csDictArr[i][#"Person"]];
[_chatDataArray addObject:_csDictArr[i][#"Message"]];
[_chatDateTimeArr addObject:_csDictArr[i][#"Time"]];
}
[self.tableView reloadData];
[self tableScrollToBottom];
}
and I put [self getDicData] in ViewDidLoad, and I also call the tableScrollToBottom in viewDidAppear
-(void)viewDidAppear:(BOOL)animated {
[self tableScrollToBottom];
}
You should use CATransaction to make sure tableView was reload completely before scroll it to bottom.
[CATransaction begin];
[CATransaction setCompletionBlock:^{
CGFloat yOffset = 0;
if (self.tableView.contentSize.height > self.tableView.bounds.size.height) {
yOffset = self.tableView.contentSize.height - self.tableView.bounds.size.height;
}
[self.tableView setContentOffset:CGPointMake(0, yOffset) animated:YES];
}];
[self.tableView reloadData];
[CATransaction commit];

UICollectionview custom flow layout delete cell

I have a horizontal UICollectionView that implements UICollectionViewLayout and uses targetContentOffsetForProposedContentOffset for a custom fling/paging functionality. Each cell is nearly the width of the screen with the next cell showing slightly to the right. The functionality works great, but I want to be able to delete the cell at index 0 when the current cell is index 1. I'm currently able to calculate and do this just fine, but upon deleting the index 0 cell it slides to the next cell (old index 2, new 1 (after deleting 0)) because of the current content offset. I'm not sure how I can delete index 0 while maintaining the current layout.
Right now in my delegate I'm doing:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
float cellWidth = self.collectionView.bounds.size.width - 20;
float currentPage = self.collectionView.contentOffset.x / cellWidth;
if (currentPage == 1) {
[self remove:0];
}
}
-(void)remove:(int)i {
[self.collectionView performBatchUpdates:^{
[self.data removeObjectAtIndex:0];
NSIndexPath *indexPath =[NSIndexPath indexPathForRow:0 inSection:0];
[self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]];
} completion:^(BOOL finished) {
}];
}
So the calculation and deletion works fine, but upon deleting [0], the collection view is scrolled to the next cell..and I'm not sure how to stop it.
I've tried self.collectionview.contentOffset = CGMakePoint(0,0) after the deleting, but the transition is still noticeably buggy. Any ideas on how to approach this problem?
so after a ton of trial and error I was able to resolve the issue. It might be a little hackish but I just wrapped the batch with a uiview animation that has no duration. Basically it overrides the deletion animation
[UIView animateWithDuration:0 animations:^{
[self.collectionView performBatchUpdates:^{
[scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
[self.data removeObjectAtIndex:0];
NSIndexPath *indexPath =[NSIndexPath indexPathForRow:0 inSection:0];
[self.collectionView deleteItemsAtIndexPaths:#[indexPath]];
[self.collectionView.collectionViewLayout invalidateLayout];
} completion:nil];
}];

UITableview scroll to top on reload goes too high?

I'm using scrollRectToVisible:
[self.tblArticle scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
and/or setContentOffset:
NSIndexPath* top = [NSIndexPath indexPathForRow:NSNotFound inSection:0];
[self.tblArticle scrollToRowAtIndexPath:top atScrollPosition:UITableViewScrollPositionTop animated:YES];
and/or this:
[self.tblArticle setContentOffset: CGPointZero animated: YES];
to (try to) scroll to the top of my tableView after reload. But sometimes it goes too high so that I see too much white space above the table. My table has a header that's above the cell rows.
It goes too high when I scroll down a bit and then initiate the reload. If I'm on top, the scrolling is good. But the lower I get before reloading, the more white space is visible above the header.
For now I'm calculating how low I am and then I set something like this:
CGFloat height = 0;
if(self.selectedCategoryID > 2)
height = 250;
[self.tblArticle scrollRectToVisible:CGRectMake(0, height, 1, 1) animated:YES];
which is veeery bad. Thanks for any suggestions!
EDIT I 'm using the uitableview reload like this:
// Reload table
[self.tblArticle reloadData];
try this:
[_mainTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[_mainTableView setContentOffset:CGPointZero animated:YES];
});
Please try this to scroll UITableview to top.
[mainTableView setContentOffset: CGPointZero animated: YES];

Keeping UITableView and UICollectionView scroll position in sync

I have a UIViewController that is able to show its content via a UICollectionView (cv) or via aUITableView (tv).
Both views are added to the view hierarchy via storyboard and I'm just hiding the one that should not be shown. Both the UICollectionView and the UITableView have the same data source.
The UICollectionView is showing the content in a two items per row grid, the UITableView obviously in a one item per row grid.
So what I want to happen is if the user decides to switch between the views the newly shown view should scroll to the element that was visible in the other view.
I did some experimenting with scrollToRowAtIndexPath:atScrollPosition:animated: and scrollToItemAtIndexPath:atScrollPosition:animated: with no success.
I understand, that both the UICollectionView and UITableView are able to return their current visible items'/rows' indexPaths, but how can i transform those indexPath to a indexPath of the other view and tell them to scroll to that element?
My current touch event handling of the switch button looks like this:
- (IBAction)switchView:(id)sender {
self.showListView = !self.showListView;
UIView *fromView, *toView;
NSIndexPath *indexPath;
if (self.showListView)
{
fromView = self.ArticleCollection;
toView = self.ArticleList;
CGRect visibleRect = (CGRect){.origin = self.ArticleCollection.contentOffset, .size = self.ArticleCollection.bounds.size};
CGPoint visiblePoint = CGPointMake(100, CGRectGetMidY(visibleRect));
indexPath = [self.ArticleCollection indexPathForItemAtPoint:visiblePoint];
}
else
{
fromView = self.ArticleList;
toView = self.ArticleCollection;
CGRect visibleRect = (CGRect){.origin = self.ArticleList.contentOffset, .size = self.ArticleList.bounds.size};
CGPoint visiblePoint = CGPointMake(100, CGRectGetMidY(visibleRect));
indexPath = [self.ArticleList indexPathForRowAtPoint:visiblePoint];
}
NSInteger row = indexPath.row;
if (self.showListView) {
[self.ArticleList scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:row*2 inSection:0]
atScrollPosition:UITableViewScrollPositionTop
animated:NO];
} else {
[self.ArticleCollection scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:ceil(row/2)
inSection:0
atScrollPosition:UICollectionViewScrollPositionCenteredVertically
animated:NO]];
}
// Here a transitionFromView:ToView:duration:options:completion call follows
}
Thanks in advance for any contribution to my problem.
Appart from a little typo inside the scrollToItemAtIndexPath:atScrollPosition:animated: call:
[self.ArticleCollection scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:row
inSection:0]
atScrollPosition:UICollectionViewScrollPositionCenteredVertically
animated:NO];
I did think indexPath.row would hold different values whether it came from the cv's visible indexPath or the tv's visible indexPath so I calculated the new row by multiplying or dividing through 2. But as it turns out the rows are identical in both cases, so I just needed to use the same value for both cases:
NSInteger row = indexPath.row;
if (self.showListView) {
[self.ArticleList scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:0]
atScrollPosition:UITableViewScrollPositionTop
animated:NO];
} else {
[self.ArticleCollection scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:row
inSection:0]
atScrollPosition:UICollectionViewScrollPositionCenteredVertically
animated:NO];
}
Sorry for the inconvenience.

Keep expanded UITableViewCell fixed on top

I have implemented SKSTableView and I used this command:
[tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
when I press a cell that is expandable, and it goes on top. Now I'd like that when I scroll the expanded cell which went to top to stay fixed there until it's closed. Can I do that?
In UITableView you have the UIScrollView methods. So you can do something like this:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
UITableViewCell *cell =[self.myTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
CGRect cellFrame = [cell convertRect:cell.frame toView:self.view];
if (self.isStickToTop) {
self.cell.frame = CGRectMake(0, 0, self.cellFrame.width, cellFrame.size.height);
}
else {
self.cell.frame = CGRectMake(0, scrollView.contentOffset.y, self.cellFrame.width, cellFrame.size.height);
}
}
The isStickToTop is your maintenance BOOLvariable that will indicate if the cell stick to top or not. Don't say u don't know ;)

Resources