Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView scrollToItemAtIndexPath not functioning properly in navigation controller

I have a method that I use to scroll to the bottom of my collectionView

- (void) scrollToBottom {
    if (_messagesArray.count > 0) {
        static NSInteger section = 0;
        NSInteger item = [self collectionView:_myCollectionView numberOfItemsInSection:section] - 1;
        if (item < 0) item = 0;
        NSIndexPath *lastIndexPath = [NSIndexPath indexPathForItem:item inSection:section];
        [_myCollectionView scrollToItemAtIndexPath:lastIndexPath atScrollPosition:UICollectionViewScrollPositionBottom animated:YES];
    }
}

And it works perfectly! I have never had a problem at any point, it works 100% consistent . . . with a modal view presentation. If however, I push the viewController onto a navigation controller, it doesn't work. Rather, it only works if there's over 15 cells. Once I reach at least 15 cells, it again begins behaving perfectly. Prior to 15 cells, it either doesn't scroll at all, or scrolls a little bit.

I realize this is a long shot, but I'm scratching my head on this one and I thought maybe somebody might know what the heck is happening.

Troubleshoots:

Have you logged to make sure it's running? YES

Have you logged index path to make sure its trying to scroll to the correct index path? YES

EXAMPLE

enter image description here

WORKING MODAL EXAMPLE

enter image description here

like image 280
Logan Avatar asked May 04 '14 16:05

Logan


3 Answers

There is a automaticallyAdjustsScrollViewInsets property in UIViewController, and as it's inherited, in UINavigationController. Set it to NO in self.navigationController and it won't adjust your insets, as documented here

like image 80
dulgan Avatar answered Oct 21 '22 16:10

dulgan


I found the problem.

The NavigationController was automatically adjusting my top content inset for some reason. I was able to prevent this behavior by adding this:

- (void) scrollToBottom {

    if (_isNavigationControllerVersion) {
        _myCollectionView.contentInset = UIEdgeInsetsZero;
    }

    if (_messagesArray.count > 0) {
        static NSInteger section = 0;
        NSInteger item = [self collectionView:_myCollectionView numberOfItemsInSection:section] - 1;
        if (item < 0) item = 0;
        NSIndexPath *lastIndexPath = [NSIndexPath indexPathForItem:item inSection:section];
        [_myCollectionView scrollToItemAtIndexPath:lastIndexPath atScrollPosition:UICollectionViewScrollPositionBottom animated:YES];
    }
}
like image 2
Logan Avatar answered Oct 21 '22 16:10

Logan


So, since your .gif demonstrates that the problem is happening when the keyboard is open, I can only assume that the bottom scroll is within the content inset of the collection view, even if it is behind the keyboard.

Be sure you're resetting the content inset when the keyboard appears/disappears. I will edit in some example code.

First, you need to register for the notifications:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWasShown:)
                                             name:UIKeyboardDidShowNotification
                                           object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide:)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];

This should go in viewDidLoad. Don't forget to removeObserver in dealloc.

Now set the content insets in these methods:

- (void)keyboardWasShown:(NSNotification *)aNotification {
    CGSize kbSize = [[[aNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets insets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    yourCollectionView.contentInset = Insets;
    yourCollectionView.scrollIndicatorInsets = Insets;
}

- (void) keyboardWillHide:(NSNotification *)aNotification {
    UIEdgeInsets insets = UIEdgeInsetsZero;
    yourCollectionView.contentInset = contentInsets;
    yourCollectionView.scrollIndicatorInsets = contentInsets;
}
like image 1
nhgrif Avatar answered Oct 21 '22 16:10

nhgrif