先看下效果图:
大家都是道UICollectionView没有提供相关的属性或方法去设置section不同的背景颜色,如果想让UICollectionView的section显示不同的背景颜色,就需要自定义一个新的布局。
自定义布局
1、自定义一个UICollectionViewSectionColorReusableView继承自UICollectionReusableView,用来作为各个分组的背景视图
class UICollectionViewSectionColorReusableView: UICollectionReusableView {
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
super.apply(layoutAttributes)
if let att = layoutAttributes as? UICollectionViewSectionColorLayoutAttributes {
backgroundColor = att.sectionBgColor
}
}
}
2、自定义一个UICollectionViewSectionColorLayoutAttributes继承UICollectionViewLayoutAttributes,里面添加一个sectionBgColor属性,用来表示section的背景颜色
class UICollectionViewSectionColorLayoutAttributes: UICollectionViewLayoutAttributes {
var sectionBgColor: UIColor?
}
3、自定义一个UICollectionViewSectionColorFlowLayout继承UICollectionViewFlowLayout,在这里计算及返回各个分组背景视图的布局属性(位置、尺寸、颜色)
class UICollectionViewSectionColorFlowLayout: UICollectionViewFlowLayout {
var decorationViewAttrs = [UICollectionViewSectionColorLayoutAttributes]()
override init() {
super.init()
register(UICollectionViewSectionColorReusableView.self, forDecorationViewOfKind: "UICollectionViewSectionColorReusableView")
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepare() {
super.prepare()
//Section个数
guard let collectionView = collectionView else { return }
let numberOfSections = collectionView.numberOfSections
guard let delegate = collectionView.delegate as? UICollectionViewSectionColorDelegateFlowLayout
else {
return
}
decorationViewAttrs.removeAll()
for section in 0..<numberOfSections {
let numberOfItems = collectionView.numberOfItems(inSection: section)
guard numberOfItems > 0,
let firstItem = layoutAttributesForItem(at: IndexPath(item: 0, section: section)),
let lastItem = layoutAttributesForItem(at: IndexPath(item: numberOfItems - 1, section: section)) else {
continue
}
var sectionInset = self.sectionInset
if let inset = delegate.collectionView?(collectionView, layout: self, insetForSectionAt: section) {
sectionInset = inset
}
var sectionFrame = firstItem.frame.union(lastItem.frame)
sectionFrame.origin.x = 0
sectionFrame.origin.y -= sectionInset.top
if scrollDirection == .horizontal {
sectionFrame.size.width += sectionInset.left + sectionInset.right
sectionFrame.size.height = collectionView.frame.height
} else {
sectionFrame.size.width = collectionView.frame.width
sectionFrame.size.height += sectionInset.top + sectionInset.bottom
}
// 2、定义视图属性
let attr = UICollectionViewSectionColorLayoutAttributes(forDecorationViewOfKind: "UICollectionViewSectionColorReusableView", with: IndexPath(item: 0, section: section))
attr.frame = sectionFrame
attr.zIndex = -1
attr.sectionBgColor = delegate.collectionView?(collectionView, layout: self, backgroundColor: section)
decorationViewAttrs.append(attr)
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let attributes = super.layoutAttributesForElements(in: rect) else { return nil }
var allAttributes = [UICollectionViewLayoutAttributes]()
allAttributes.append(contentsOf: attributes)
for att in decorationViewAttrs {
if rect.intersects(att.frame) {
allAttributes.append(att)
}
}
return allAttributes
}
}
4、新增一个协议方法,用于在外面通过该方法设置背景色
@objc protocol UICollectionViewSectionColorDelegateFlowLayout: UICollectionViewDelegateFlowLayout {
@objc optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, backgroundColor section: Int) -> UIColor
}
以上就是自定义布局的全过程,总结一下就四步:
1、自定义一个UICollectionViewSectionColorReusableView继承自UICollectionReusableView,用来作为各个分组的背景视图
2、自定义一个UICollectionViewSectionColorLayoutAttributes继承UICollectionViewLayoutAttributes,里面添加一个sectionBgColor属性,用来表示section的背景颜色
3、自定义一个UICollectionViewSectionColorFlowLayout继承UICollectionViewFlowLayout,在这里计算及返回各个分组背景视图的布局属性(位置、尺寸、颜色)
4、新增一个协议方法,用于在外面通过该方法设置背景色
现在我们就来写个demo试试效果
使用案列
1、创建一个UICollectionView,collectionViewLayout使用UICollectionViewSectionColorFlowLayout
private lazy var collectionView: UICollectionView = {
let layout = UICollectionViewSectionColorFlowLayout()
layout.itemSize = CGSize(width: (UIScreen.main.bounds.size.width - 51) / 4, height: 65)
layout.minimumLineSpacing = 10
layout.minimumInteritemSpacing = 10
layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
let collectionView = UICollectionView(frame: UIScreen.main.bounds, collectionViewLayout: layout)
collectionView.backgroundColor = .gray
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self,
forCellWithReuseIdentifier: "UICollectionViewCell")
collectionView.showsVerticalScrollIndicator = false
return collectionView
}()
2、遵守UICollectionViewSectionColorDelegateFlowLayout协议,设置不同section背景颜色
extension ViewController: UICollectionViewSectionColorDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, backgroundColor section: Int) -> UIColor {
switch section {
case 0:
return .green
case 2:
return .blue
case 3:
return .cyan
case 4:
return .purple
default:
return .orange
}
}
}
到此就结束了