I have one CollectionViewController and have 10 cells in it.
But when I run the app it displays the cell at bottom, but I want to display it from top cell at viewDidLoad.
I tried many things but it didn't work.
How to fix it?
in swift 3: after reloadData()
self.collectionView.setContentOffset(CGPoint(x:0,y:0), animated: true)
Its work fine......
collectionView.setContentOffset(.zero, animated: false)
Add this line after reloading the collection view.
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionTop animated:NO];
Edit:
Just want to add one more point here is if collectionView datasource has ZERO elements or it is nil then above code will not work and probably crash your app.
Write condition to check that datasource is available or not!
if (self.dataArray.count > 0) {
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionTop animated:NO];
}
Where, dataArray is your datasource.
Add this piece of code after reloading the collection view:
swift
yourCollectionView.setContentOffset(CGPoint.zero, animated: true)
objective-c
[yourCollectionView setContentOffset:CGPointZero animated:YES];
Swift 4 Swift 5
Actually, it's work just do
collectionView.setContentOffset(.zero, animated: false)
But, if in case your CollectionView implement .contentInset or outer margin, let's say margin top & bottom is set 16, this code will actually back to the top.
collectionView.setContentOffset(CGPoint(x: 0, y: -16), animated: true)
Please try this one
[self.yourcollectionview scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionTop animated:NO];
Make animated option false. Maybe some view animations are running during your collection view animation process.
collectionView.scrollToItem(at: indexPath, at: .top, animated: false)
To display the data from top cell in collectionView you can use one method
[collectionView setScrollsToTop:YES];
Hope it will Help You.
Related
Problem
I need to have a UITableView reload with a specific cell positioned at the top of the tableview. For instance, have the 3rd cell in the tableView appear at the top of the tableView, rather than the 1st.
The issue in doing this comes from not being able to use the
self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
function, because I have a custom header that expands and collapse when the user scrolls. That means when I call the scrollToRow() function, my header collapses, messing things up.
Question
Is there any way to have a tableView open/reload with the 3rd cell positioned at the top of the tableView without using a "scroll" function?
Thanks!
You can follow below steps to fulfill your requirement:
Identify NSIndexPath of one of the visible cells.
Get its rectForRowAtIndexPath.
Get the current contentOffset of the table, itself.
Or, you can use scrollRectToVisible
This is how we use contentOffset:
mainTableView.setContentOffset(rectForRowAtIndexPath.point, animated: true)
And scrollRectToVisible:
mainTableView.scrollRectToVisible(rectForRowAtIndexPath.point, animated: true)
On reloading the UICollectionView some time CollectionView cell does not bounce back. see the image collectionCell with title "Bgrawal ji Sourabh" should not be at this much distance from right side.It should have bounce.
Try this:
[self.collectionView scrollToItemAtIndexPath:yourDesiredIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO];
Please add below code before when your reload your collectionView
let indexes = NSIndexPath(forItem: 0, inSection: 0)
self.collectionViewSecond.scrollToItemAtIndexPath(indexes, atScrollPosition: .None, animated: false)
It's work for me hope work for you also!
Make sure you have enabled these two option in the CollectionView attribute Inspector i.e. Bounce on Scroll and Bounce on zoom this will allow the collectionView to give a bounce feed back on the scroll.
When my View (containing a Table View) loads, I want it to scroll to the bottom of the table view. This works great. However, when one of my buttons (sendReply) is tapped, I also want the tableView to scroll to the bottom. For some reason, scrolling to the bottom of the tableView works when the View is initially loaded, however [self bottomScroll:self] doesn't seem to fire when I place it inside of my sendReply action?
.m
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self bottomScroll:self];
}
- (void)bottomScroll:(id)sender {
if (self.messages.count > 0)
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.messages.count-1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
- (IBAction)sendReply:(id)sender {
[self bottomScroll:self];
}
This should work. Are you sure messages.count is greater than 0 when you tap the button? You can set a breakpoint at that line and see if this code is executed.
Also you can try -scrollRectToVisible as an alternative.
as phi stated scrollRectToVisible would be the way I would go. Call your tableView's scroll view passing in the rect of your button you want to show. It's been awhile since I've used obj-c but:
-(IBAction)sendReply: (id)sender {
[scrollView scrollRectToVisible: sendReply.frame, animated: YES]
}
? The syntax may be wrong there but it should be close enough to get you where you are going.
In swift:
#IBAction func sendReply(sender: UIButton/AnyObject) -> Void {
let scrollView = tableView.scrollView
scrollView.scrollrectToVisible(_ rect: sender.frame, animated: true)
}
It seems strange based on your description. Need more code to find whats going on. What can be inferred is you want to scroll the last cell to the bottom. So make sure the contentsize of tableview is larger than its frame vertically.
Try this one
if (self.tableView.contentSize.height > self.tableView.frame.size.height){
CGPoint point = CGPointMake(0, self.tableView.contentSize.height - self.tableView.frame.size.height);
[self.tableView setContentOffset:point];
}
In iOS 7, I use the following code to scroll to the top of my UITableView. You have to account for the overlap of the translucent status bar and navigation bar.
[tableView
setContentOffset:CGPointMake(
0.0,
-tableViewController.topLayoutGuide.length
)
animated:YES
];
This works only works after the first time you call it. On the first time you call it, my table gets scrolled much farther than it should, showing a lot of white space. Additionally, the UIRefreshControl appears frozen. You have to nudge the table a little to make it bounce back to the true top. Afterwards, you can call this code as many times as you want and it behaves as you'd expect it.
I've tried other ways, but they all have problems. The iOS 6 way behaves just as oddly on the first call. Although it doesn't jump a huge amount on subsequent calls, they are not correct because it scrolls to 64.0 points below the top of the table because we forgot to account for the status and navigation bar.
[table setContentOffset:CGPointZero animated:YES];
I've also tried scrolling to the first cell, but it doesn't scroll to the very top in one call. It will only scroll up one page's worth every time you call it.
[tableView
scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
atScrollPosition:UITableViewScrollPositionTop
animated:YES
];
Try this one:
NSIndexPath* top = [NSIndexPath indexPathForRow:NSNotFound inSection:0];
[tableView scrollToRowAtIndexPath:top atScrollPosition:UITableViewScrollPositionTop animated:YES];
In SWIFT
let top = NSIndexPath(forRow: NSNotFound , inSection: 0)
tableView.scrollToRowAtIndexPath(top, atScrollPosition: .Bottom, animated: true)
Swift 4.0 and above
let top = NSIndexPath(row: NSNotFound, section: 0)
tableView.scrollToRow(at: top as IndexPath, at: .bottom, animated: true)
i looked at other answers and found the following solution that worked for me.
-(void) scrollToTop
{
if ([self numberOfSectionsInTableView:self.tableView] > 0)
{
NSIndexPath* top = [NSIndexPath indexPathForRow:NSNotFound inSection:0];
[self.tableView scrollToRowAtIndexPath:top atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
Hope, it solves your problem.
it's not "magic". The 64 offset is for status bar(20 points) and navigation bar(44 points) heights. If the scrollview have offset of 0 and you also have status bar + navigation bar, it would be under these objects and you will see -64.0 of your original content. In storyboard there is an option "Adjust scroll view insets" and this is checked by default
Try:
[tableView
setContentOffset:CGPointMake(
tableView.contentOffset.x,
-tableView.contentInset.top
)
animated:YES
];
Please try this:
- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;
The sample is like this:
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:0 animated:YES];
In Objective-C
[mainTableView setContentOffset:CGPointZero animated:YES];
And in Swift:
mainTableView.setContentOffset(CGPointZero, animated:true)
In Objective C
NSIndexPath* top = [NSIndexPath indexPathForRow:NSNotFound inSection:0];
[self.tableView scrollToRowAtIndexPath:top atScrollPosition:UITableViewScrollPositionTop animated:YES];
In Swift
var scrollIndexPath: NSIndexPath = NSIndexPath(forRow:NSNotFound , inSection: 0)
self.tableview.scrollToRowAtIndexPath(scrollIndexPath, atScrollPosition: UITableViewScrollPosition.top, animated: true)
iOS scrollview is behaving a bit oddly. The 64.0 offset was added "magically" to the first scrollview in the view hierarchy "the first time" as you mentioned. I haven't figured out why this was happening. At the moment I only had a really hackish solution: you can add a dummy scroll as the first scrolling in the view hierarchy, with height set as 0. After that, you solution should work as usual.![enter image description here][1]
screenshot : http://imgur.com/LvrbcqG
Hope this helps.
Anyone else know why this is happening in the first place ?
I'm trying to figure out how to scroll all the way to the bottom of a UICollectionView when the screen first loads. I'm able to scroll to the bottom when the status bar is touched, but I'd like to be able to do that automatically when the view loads as well. The below works fine if I want to scroll to the bottom when the status bar is touched.
- (BOOL)scrollViewShouldScrollToTop:(UITableView *)tableView
{
NSLog(#"Detect status bar is touched.");
[self scrollToBottom];
return NO;
}
-(void)scrollToBottom
{//Scrolls to bottom of scroller
CGPoint bottomOffset = CGPointMake(0, collectionViewReload.contentSize.height - collectionViewReload.bounds.size.height);
[collectionViewReload setContentOffset:bottomOffset animated:NO];
}
I've tried calling [self scrollToBottom] in the viewDidLoad. This isn't working. Any ideas on how I can scroll to the bottom when the view loads?
I found that nothing would work in viewWillAppear. I can only get it to work in viewDidLayoutSubviews:
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:endOfModel inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
}
Just to elaborate on my comment.
viewDidLoad is called before elements are visual so certain UI elements cannot be manipulated very well. Things like moving buttons around work but dealing with subviews often does not (like scrolling a CollectionView).
Most of these actions will work best when called in viewWillAppear or viewDidAppear. Here is an except from the Apple docs that points out an important thing to do when overriding either of these methods:
You can override this method to perform additional tasks associated
with presenting the view. If you override this method, you must call
super at some point in your implementation.
The super call is generally called before custom implementations. (so the first line of code inside of the overridden methods).
So had a similar issue and here is another way to come at it without using scrollToItemAtIndexPath
This will scroll to the bottom only if the content is larger than the view frame.
It's probably better to use scrollToItemAtIndexPath but this is just another way to do it.
CGFloat collectionViewContentHeight = myCollectionView.contentSize.height;
CGFloat collectionViewFrameHeightAfterInserts = myCollectionView.frame.size.height - (myCollectionView.contentInset.top + myCollectionView.contentInset.bottom);
if(collectionViewContentHeight > collectionViewFrameHeightAfterInserts) {
[myCollectionView setContentOffset:CGPointMake(0, myCollectionView.contentSize.height - myCollectionView.frame.size.height) animated:NO];
}
Swift 3 example
let sectionNumber = 0
self.collectionView?.scrollToItem(at: //scroll collection view to indexpath
NSIndexPath.init(row:(self.collectionView?.numberOfItems(inSection: sectionNumber))!-1, //get last item of self collectionview (number of items -1)
section: sectionNumber) as IndexPath //scroll to bottom of current section
, at: UICollectionViewScrollPosition.bottom, //right, left, top, bottom, centeredHorizontally, centeredVertically
animated: true)
Get indexpath for last item. Then...
- (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated
For me, i found next solution:
call reloadData in CollectionView, and make dcg on main to scroll.
__weak typeof(self) wSelf = self;
[wSelf.cv reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"HeightGCD:%#", #(wSelf.cv.contentSize.height));
[wSelf.cv scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:50 inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:YES];
});
none of these were working so well for me, I ended up with this which will work on any scroll view
extension UIScrollView {
func scrollToBottom(animated: Bool) {
let y = contentSize.height - 1
let rect = CGRect(x: 0, y: y + safeAreaInsets.bottom, width: 1, height: 1)
scrollRectToVisible(rect, animated: animated)
}
}
The issue is likely that even if your collection view is on screen, it might not have the actual contentSize.
If you scroll in viewDidAppear, you will have a contentSize, but your scollectionview will briefly show content before scrolling.
And the problem with viewDidLayoutSubviews is that it is called multiple times, so you then need to add an ugly boolean to limit scrolling.
The best solution i've found is to force layout in view will appear.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// force layout before scrolling to most recent
collectionView.layoutIfNeeded()
// now you can scroll however you want
// e.g. scroll to the right
let offset = collectionView.contentSize.width - collectionView.bounds.size.width
collectionView.setContentOffSet(CGPoint(x: offset, y: 0), animated: animated)
}
Consider if you can use performBatchUpdates like this:
private func reloadAndScrollToItem(at index: Int, animated: Bool) {
collectionView.reloadData()
collectionView.performBatchUpdates({
self.collectionView.scrollToItem(at: IndexPath(item: index, section: 0),
at: .bottom,
animated: animated)
}, completion: nil)
}
If index is the index of the last item in the collection's view data source it'll scroll all the way to the bottom.