日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

UICollectionView的sectionHeader悬浮效果

發布時間:2024/4/17 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UICollectionView的sectionHeader悬浮效果 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

collectionView沒有類似于tableView的Plain效果(即sectionHeader懸浮),不過可以通過自定義flowLayout實現,因此它比tableView擁有更強大的擴展性,這點是毋庸置疑的。

在項目中相關列表頁的實現,我更傾向于使用UIColletionView,這個因人而異。

下面的代碼是我參考XLPlainFlowLayout轉換成Swift來的(就是copy+學習),在此感謝源代碼的分享。

####MTPlainFlowLayout.swift

import UIKitclass MTPlainFlowLayout: UICollectionViewFlowLayout {// 設置停留位置,默認為64(沒有導航欄同樣設置有效)var naviHeight: CGFloat = 64override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {// UICollectionViewLayoutAttributes:稱它為collectionView中的item(包括cell和header、footer這些)的《結構信息》var attributesArray: [UICollectionViewLayoutAttributes] = []if let superAttributesArray = super.layoutAttributesForElementsInRect(rect) {attributesArray = superAttributesArray}// 創建存索引的數組,無符號(正整數),無序(不能通過下標取值),不可重復(重復的話會自動過濾)let noneHeaderSections = NSMutableIndexSet()// 遍歷superArray,得到一個當前屏幕中所有的section數組for attributes in attributesArray {// 如果當前的元素分類是一個cell,將cell所在的分區section加入數組,重復的話會自動過濾if attributes.representedElementCategory == .Cell {noneHeaderSections.addIndex(attributes.indexPath.section)}}// 遍歷superArray,將當前屏幕中擁有的header的section從數組中移除,得到一個當前屏幕中沒有header的section數組// 正常情況下,隨著手指往上移,header脫離屏幕會被系統回收而cell尚在,也會觸發該方法for attributes in attributesArray {if let kind = attributes.representedElementKind {//如果當前的元素是一個header,將header所在的section從數組中移除if kind == UICollectionElementKindSectionHeader {noneHeaderSections.removeIndex(attributes.indexPath.section)}}}// 遍歷當前屏幕中沒有header的section數組noneHeaderSections.enumerateIndexesUsingBlock { (index, stop) in// 取到當前section中第一個item的indexPathlet indexPath = NSIndexPath(forRow: 0, inSection: index)// 獲取當前section在正常情況下已經離開屏幕的header結構信息if let attributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: indexPath) {// 如果當前分區確實有因為離開屏幕而被系統回收的header,將該header結構信息重新加入到superArray中去attributesArray.append(attributes)}}// 遍歷superArray,改變header結構信息中的參數,使它可以在當前section還沒完全離開屏幕的時候一直顯示for attributes in attributesArray {if attributes.representedElementKind == UICollectionElementKindSectionHeader {let section = attributes.indexPath.sectionlet firstItemIndexPath = NSIndexPath(forRow: 0, inSection: section)var numberOfItemsInSection = 0// 得到當前header所在分區的cell的數量if let number = self.collectionView?.numberOfItemsInSection(section) {numberOfItemsInSection = number}// 得到最后一個item的indexPathlet lastItemIndexPath = NSIndexPath(forRow: max(0, numberOfItemsInSection-1), inSection: section)// 得到第一個item和最后一個item的結構信息let firstItemAttributes: UICollectionViewLayoutAttributes!let lastItemAttributes: UICollectionViewLayoutAttributes!if numberOfItemsInSection > 0 {// cell有值,則獲取第一個cell和最后一個cell的結構信息firstItemAttributes = self.layoutAttributesForItemAtIndexPath(firstItemIndexPath)lastItemAttributes = self.layoutAttributesForItemAtIndexPath(lastItemIndexPath)} else {// cell沒值,就新建一個UICollectionViewLayoutAttributesfirstItemAttributes = UICollectionViewLayoutAttributes()// 然后模擬出在當前分區中的唯一一個cell,cell在header的下面,高度為0,還與header隔著可能存在的sectionInset的toplet itemY = attributes.frame.maxY + self.sectionInset.topfirstItemAttributes.frame = CGRect(x: 0, y: itemY, width: 0, height: 0)// 因為只有一個cell,所以最后一個cell等于第一個celllastItemAttributes = firstItemAttributes}// 獲取當前header的framevar rect = attributes.frame// 當前的滑動距離 + 因為導航欄產生的偏移量,默認為64(如果app需求不同,需自己設置)var offset_Y: CGFloat = 0if let y = self.collectionView?.contentOffset.y {offset_Y = y}offset_Y = offset_Y + naviHeight// 第一個cell的y值 - 當前header的高度 - 可能存在的sectionInset的toplet headerY = firstItemAttributes.frame.origin.y - rect.size.height - self.sectionInset.top// 哪個大取哪個,保證header懸停// 針對當前header基本上都是offset更加大,針對下一個header則會是headerY大,各自處理let maxY = max(offset_Y, headerY)// 最后一個cell的y值 + 最后一個cell的高度 + 可能存在的sectionInset的bottom - 當前header的高度// 當當前section的footer或者下一個section的header接觸到當前header的底部,計算出的headerMissingY即為有效值let headerMissingY = lastItemAttributes.frame.maxY + self.sectionInset.bottom - rect.size.height// 給rect的y賦新值,因為在最后消失的臨界點要跟誰消失,所以取小rect.origin.y = min(maxY, headerMissingY)// 給header的結構信息的frame重新賦值attributes.frame = rect// 如果按照正常情況下,header離開屏幕被系統回收,而header的層次關系又與cell相等,如果不去理會,會出現cell在header上面的情況// 通過打印可以知道cell的層次關系zIndex數值為0,我們可以將header的zIndex設置成1,如果不放心,也可以將它設置成非常大attributes.zIndex = 1024}}return attributesArray}override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {return true}} 復制代碼

注意: 1.上述自定義flowLayout里存在一個bug,代碼里使用的self.sectionInset是初始化UICollectionViewFlowLayout設置的sectionInset,而不會隨著代理方法:func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets返回的sectionInset去更新; 2.如果初始化UICollectionViewFlowLayout并且只有一組section的時候設置sectionInset,是沒有上述問題的; 3.如果有多組section,同時需要動態設置每組的sectionInset的話,那么就會sectionHeader與預期效果就會有一定的偏差,這個偏差就是因為上述1的bug所造成的。 4.OC版本也有同樣上述問題

···

解決辦法: 1.如果只有一組section的話可以選擇在初始化flowLayout的時候設置sectionInset; 2.多組section的話就不建議使用上述1的方式,而是選擇 UICollectionViewDelegateFlowLayout里的代理方法func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets去動態設置當前section的sectionInset,這樣上面的bug就可以避免了; 3.以上兩個方法大家因情況而選擇,如果大家有更好的解決方案或者自定義flowLayout請留言或在本文底部評論; 4.OC版同樣可使用上面的解決方案。


####如何使用 上面貼出來的代碼就是完整的Swift文件,直接使用 MTPlainFlowLayout創建UICollectionViewFlowLayout對象使用即可。

圖片示例:

轉載于:https://juejin.im/post/5a3321976fb9a045204c419f

總結

以上是生活随笔為你收集整理的UICollectionView的sectionHeader悬浮效果的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。