CollectionView的HeaderView頭視圖懸停

上一篇我寫了關于CollectionView的HeaderView頭視圖的添加的方法和實現,現在又需要在滑動的時候像TableView的section一樣在頂部懸停,在網上搜索了一些文章也比較少提到collectionView頭視圖懸停的,而且也不是瀑布流布局的。有幾篇寫的也是同一個地方復制的,看不太懂。
后來在github上有一個SYStickHeaderWaterFall 寫了這個懸停程序https://github.com/zhangsuya/SYStickHeaderWaterFall
參考這個程序寫了一些出來,琢磨了很久也沒搞出來,因為在里面寫的瀑布流布局方法有些不同,所以還是參考他的原理來寫出了這個懸停程序,這里只針對一個secion的來寫的,多個的時候可能會有點問題。
先看一下我的設計原理圖,

臨界點懸停.png
超過臨界點懸停.png

這里寫一下關鍵部分的代碼,其他關于流布局聚合頭視圖添加的代碼看上一篇的相關代碼吧!
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其實是在向下移動,這個視覺差就產生了懸停。
看一下效果圖吧,
懸停前和懸停時的效果圖,

懸停時.png
懸停.png

之前的一些布局效果,

目錄.png
基本瀑布流.png
第一個cell自定義.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容