UICollectionView contentOffset changes with custom layout
Asked Answered
J

5

27

I have a UICollectionView with a custom UICollectionViewLayout (actually, I'm using this nice layout).

I set contentOffset = CGPointZero in viewDidLoad. After viewDidLoad, however, the offset is -20, and the content gets pushed down like so:


picture

(It should be flush with the line). I'm loading the collection view layout in interface builder. It seems that my problem is very similar to this one, however the solutions there don't work for me.

I tried modifying collectionViewContentSize in my layout implementation to ensure it was always greater than the size of the collectionView. Although this means I can scroll my content down (it's shorter than the height of the collectionView) and hide the extra space, I can also scroll back up to see it.

Nothing seems to work!

Joellyn answered 16/7, 2013 at 22:42 Comment(2)
This is a "soft bug" even today (2023) in UIKit. It comes down to the behavior of the (totally insane) contentInsetAdjustmentBehavior system (which should never have been in UIKit and is just silly and stupid). The issue is the ".never" mode (the only one anyone ever uses) has some obscure either bugs or soft bugs or erratic behavior, when, you have complex systems of scrollviews (like table views and/or collection views) on the same screen; they interact with each other in weird and confusing ways in different parts of the view cycle. If you build truly complicated screens it's PITAUnhand
there's a further incredibly confusing issue, which is the totally undocumented behavior mentioned by me here at "Bizarre subtle gotchya": https://mcmap.net/q/63362/-why-is-there-extra-padding-at-the-top-of-my-uitableview-with-style-uitableviewstylegrouped-in-ios7Unhand
J
16

The only solution I could come up with that had barely-acceptable behavior:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (self.collectionView.contentOffset.y < 0) {
        self.collectionView.contentOffset = CGPointMake(self.collectionView.contentOffset.x, 0.0);
    }
}

As well as setting the height of the content to fmax(self.collectionView.frame.size.height + 20, [self stackedSectionHeight]) in collectionViewContentSize

This removes the space above the section header, but it removes the "bounce" from the top. A pretty sub-optimal solution, but fairly acceptable.

I'll accept a better answer if anyone has one, or if I find one I'll update this answer.

Joellyn answered 18/7, 2013 at 23:39 Comment(3)
I have a similar problem when using horizontal layout.Sogdian
In veritacal layout the content is OK. when changing the layout object to be horizontal all of the content disappearsSogdian
Same issue and same solution I found. I get this only on iOS7 SDK and only when running on iOS7. Most strange thing is that another scrollView in other viewController haven't this issue.. I break my head, but not found a reasonInjection
I
51

I found the reason why this happens. Check the accepted answer from this question: Status bar and navigation bar appear over my view's bounds in iOS 7

Indeed, we could just set edgesForExtendedLayout or automaticallyAdjustsScrollViewInsets properties of UIViewController in IB (if you use Storyboard) of in viewDidLoad and it will fix our issue.

Just don't forget check for this property is available, because in iOS6 or prior it will cause crash:

if ([self respondsToSelector:@selector(setAutomaticallyAdjustsScrollViewInsets:)]) {
    self.automaticallyAdjustsScrollViewInsets = NO;
}

Regards!

Injection answered 8/10, 2013 at 8:51 Comment(4)
Note that if you have a collection view controller contained in a parent view controller, you have to set automaticallyAdjustsScrollViewInsets on the parent controller.Ong
I had a case where I wanted to place a collectionView with 74h by 30w cells which were being offset by -44 every time I moved from parent view controller to another. Tried to solve this for almost two hours by trying so many wrong ways. Thanks.Planter
The accepted answer you are referring to does not mention anything about a custom layout.Xerophagy
@bio, true, though I don’t think it actually matters in this case.Injection
J
16

The only solution I could come up with that had barely-acceptable behavior:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (self.collectionView.contentOffset.y < 0) {
        self.collectionView.contentOffset = CGPointMake(self.collectionView.contentOffset.x, 0.0);
    }
}

As well as setting the height of the content to fmax(self.collectionView.frame.size.height + 20, [self stackedSectionHeight]) in collectionViewContentSize

This removes the space above the section header, but it removes the "bounce" from the top. A pretty sub-optimal solution, but fairly acceptable.

I'll accept a better answer if anyone has one, or if I find one I'll update this answer.

Joellyn answered 18/7, 2013 at 23:39 Comment(3)
I have a similar problem when using horizontal layout.Sogdian
In veritacal layout the content is OK. when changing the layout object to be horizontal all of the content disappearsSogdian
Same issue and same solution I found. I get this only on iOS7 SDK and only when running on iOS7. Most strange thing is that another scrollView in other viewController haven't this issue.. I break my head, but not found a reasonInjection
I
7

I started to find this issue appearing on iOS 11 where I had a scrollview within a scroll view. Took me almost a day to figure it out.

Try setting the content inset adjustment behaviour:

if #available(iOS 11.0, *) {
    scrollView.contentInsetAdjustmentBehavior = .never
}

This fixed my collectionview adjusting it's content inset down a small amount as the collectionview frame would move past the safe area of the enclosing scrollview.

Intrados answered 30/1, 2018 at 23:31 Comment(0)
T
1
let oldContentSizeHeight: CGFloat = self.colName.contentSize.height
        self.colName.reloadData()
        self.colName.layoutIfNeeded()
        self.view.layoutIfNeeded()
        self.colName.contentOffset.y = self.colName.contentOffset.y + (self.colName.contentSize.height - oldContentSizeHeight)
Tousle answered 1/1, 2019 at 10:10 Comment(0)
L
0

This is the swift 4.2 version of the correct answer but to make this workable you have to add the protocol UIScrollViewDelegate:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if self.collectionView.contentOffset.y < 0 {
        self.collectionView.contentOffset = CGPoint(x: self.collectionView.contentOffset.x, y: 0.0)
    }
}
Lynxeyed answered 10/1, 2019 at 13:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.