上一篇我寫了關于CollectionView的HeaderView
頭視圖的添加的方法和實現,現在又需要在滑動的時候像TableView的section
一樣在頂部懸停,在網上搜索了一些文章也比較少提到collectionView
頭視圖懸停的,而且也不是瀑布流布局的。有幾篇寫的也是同一個地方復制的,看不太懂。
后來在github上有一個SYStickHeaderWaterFall
寫了這個懸停程序https://github.com/zhangsuya/SYStickHeaderWaterFall
參考這個程序寫了一些出來,琢磨了很久也沒搞出來,因為在里面寫的瀑布流布局方法有些不同,所以還是參考他的原理來寫出了這個懸停程序,這里只針對一個secion的來寫的,多個的時候可能會有點問題。
先看一下我的設計原理圖,
這里寫一下關鍵部分的代碼,其他關于流布局聚合頭視圖添加的代碼看上一篇的相關代碼吧!
在UICollectionViewFlowLayout
布局文件中,設置AttributesArray
的方法里獲取到之前添加過的頭視圖Attribute,并設置他的位置來實現懸停,
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
[self sectionHeaderStickCounter];//計算Header停留
return self.attributeArray;
}
#pragma mark - Header停留算法
- (void)sectionHeaderStickCounter
{
if (self.isStickyHeader) {
for (UICollectionViewLayoutAttributes *layoutAttributes in self.attributeArray) {
if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
// 這里第1個cell是根據自己存放attribute的數組而定的
UICollectionViewLayoutAttributes *firstCellAttrs = self.attributeArray[1];
CGFloat headerHeight = CGRectGetHeight(layoutAttributes.frame);
CGPoint origin = layoutAttributes.frame.origin;
// 懸停臨界點的計算,self.stickHight默認設置為64
if (headerHeight-self.collectionView.contentOffset.y <= self.stickHight) {
origin.y = self.collectionView.contentOffset.y - (headerHeight - self.stickHight);
}
CGFloat width = layoutAttributes.frame.size.width;
layoutAttributes.zIndex = 2048;//設置一個比cell的zIndex大的值
layoutAttributes.frame = (CGRect){
.origin = origin,
.size = CGSizeMake(width, layoutAttributes.frame.size.height)
};
NSLog(@"offset = %f Y=%f\nitemY=%f",self.collectionView.contentOffset.y,layoutAttributes.frame.origin.y,firstCellAttrs.frame.origin.y);
}
}
}
}
//不設置這里看不到懸停
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES;
}
結合原理圖可以看出,要實現懸停,就是獲取Header的Attribute
,然后在滑動到達懸停位置時,不再讓header的Y坐標繼續往上移動,
這時,設置header的origin.y
就成為了關鍵點。我們知道到達臨界點,也就是頭視圖滑動到只能看到你所設置的懸停高度的那一部分時就不再往上滾動了,但其他視圖還要上移。那我需要計算出這時頭視圖已經越過懸停邊界的部分的高度,再根據```collectionView的Y``軸偏移量,利用他們間的規律寫出這個計算方法,這樣header其實是在向下移動,這個視覺差就產生了懸停。
看一下效果圖吧,
懸停前和懸停時的效果圖,
之前的一些布局效果,