寫在前面
這一系列文章是最近寫的一款簡單的音樂播放器中涉及到的一些比較實用的技術,希望能對大家的開發提供幫助,這是播放器的Github地址。
自定義UICollectionViewFlowLayout
關于UICollectionView,業務中還是會很經常用到的,一般app的首頁都會采用UICollectionView來定制,它靈活度高,使用起來也不是很麻煩,還可以實現很多很炫酷的效果,這篇文章就是講的如何使UICollectionView的某一個SectionHeader能夠實現懸浮的效果。這是效果圖:
其實如果想讓UICollectionView的所有SectionHeader都能懸浮,那很簡單,只要設置FlowLayout的
sectionHeadersPinToVisibleBounds
為true就OK了,但這僅在iOS9中才支持這種設置,
let layout = UICollectionViewFlowLayout()
layout.sectionHeadersPinToVisibleBounds = true
那如果我們的系統需要適配之前的iOS版本,又或者我們僅僅需要讓某一個SectionHeader支持懸浮呢?這時候就需要我們自定義layout了:
let _naviHeight : CGFloat = 0
// 需要保持懸浮的sectionIndex
let pinSectionIndex = 2
class FindMusicCollectionLayout: UICollectionViewFlowLayout, UICollectionViewDelegateFlowLayout {
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
// 獲取父類返回的所有item的layout信息
var superArray = NSArray(array: super.layoutAttributesForElementsInRect(rect)!, copyItems: true) as! [UICollectionViewLayoutAttributes]
let indexPath = NSIndexPath.init(forItem: 0, inSection: pinSectionIndex)
// 獲取當前section在正常情況下已經離開屏幕的header的信息
let attributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: indexPath)
if let attributes = attributes {
superArray.append(attributes)
}
// 遍歷superArray的sectionHeader信息,使它可以在當前section還沒完全離開屏幕的時候一直顯示
for attributes in superArray {
if attributes.representedElementKind == UICollectionElementKindSectionHeader && attributes.indexPath.section == pinSectionIndex {
// 得到當前header所在分區的cell的數量
let numberOfItemsInSection = self.collectionView!.numberOfItemsInSection(attributes.indexPath.section)
// 得到第一個item的indexPath
let firstItemIndexPath = NSIndexPath.init(forItem: 0, inSection: attributes.indexPath.section)
var firstItemAttributes : UICollectionViewLayoutAttributes!
if numberOfItemsInSection > 0 {
firstItemAttributes = self.layoutAttributesForItemAtIndexPath(firstItemIndexPath)
} else {
firstItemAttributes = UICollectionViewLayoutAttributes()
let y = CGRectGetMaxY(attributes.frame) + self.sectionInset.top
firstItemAttributes.frame = CGRectMake(0, y, 0, 0)
}
var rect = attributes.frame
let offset = self.collectionView!.contentOffset.y + _naviHeight
let headerY = firstItemAttributes.frame.origin.y - rect.height - self.sectionInset.top
// 設置section的Y值,確保section懸浮在屏幕上方
let maxY = max(offset, headerY)
rect.y = maxY
attributes.frame = rect
// 這里的zIndex需要大于10,不然會被別的attributes覆蓋掉
attributes.zIndex = 20
}
}
return superArray
}
override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
return true
}
}