Native contacts app has interesting effect - when user tries to scroll, the scroll view pushes the top view with avatar and only when top view is in "small mode" it is scrolled up.
I was able to resize view on scrolling, via didScroll
method. But problem is, content offset is also changing while i push the top vied. In native contacts, content offset changes only when top view is in "small mode"
Any suggestions, how did they made this?
The bounty answer is good, but it still gives somewhat choppy solution to this problem. If you want exacly like native this is your solution. I have been playing a lot lately with collection views, and have gained much more experience. One of the things that I found is that this problem can easily be solved with custom layout:
class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout {
let minHeightForHeader: CGFloat = 50
let offsetFromTop: CGFloat = 20
override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
// get current attributes
let attributes = super.layoutAttributesForSupplementaryView(ofKind: elementKind, at: indexPath)
// get first section
if let attributes = attributes, elementKind == UICollectionElementKindSectionHeader && indexPath.section == 0 {
if let collectionView = collectionView {
// now check for content offset
var frame = attributes.frame
let yOffset = collectionView.contentOffset.y
if yOffset >= -offsetFromTop {
let calculatedHeight = frame.size.height - (yOffset + offsetFromTop)
let maxValue = minHeightForHeader > calculatedHeight ? minHeightForHeader : calculatedHeight
frame.size.height = maxValue
attributes.frame = frame
}
else {
frame.origin.y = offsetFromTop + yOffset
attributes.frame = frame
}
}
return attributes
}
// default return
return attributes
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
Just replace your default layout with this custom class and add this line somewhere in your setup method
flowLayout.sectionHeadersPinToVisibleBounds = true
Voila!
EDIT: Just one more optional method for clipping part, when you scroll to certain part, scroll might continue or return:
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
if let collectionView = collectionView {
let yOffset = collectionView.contentOffset.y
if yOffset + offsetFromTop >= maxHeightForHeader / 2 && yOffset + offsetFromTop < maxHeightForHeader && !(velocity.y < 0) || velocity.y > 0{
return CGPoint.init(x: 0, y: maxHeightForHeader - minHeightForHeader - offsetFromTop)
}
if yOffset + offsetFromTop < maxHeightForHeader / 2 && yOffset + offsetFromTop > 0 || velocity.y < 0 {
return CGPoint.init(x: 0, y: -offsetFromTop)
}
}
return proposedContentOffset
}