import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var collectionView: UICollectionView!
let colors: [UIColor] = [.red, .green, .gray, .yellow, .orange, .purple, .brown, .blue, .cyan]
var columnWidths = [CGFloat]()
var numberOfRows = 30
override func viewDidLoad() {
super.viewDidLoad()
// 創(chuàng)建和配置自定義布局
let layout = CustomFlowLayout()
layout.columnWidths = [100, 150, 80, 120, 200] // 示例寬度,根據(jù)需要設(shè)置
layout.numberOfRows = numberOfRows
layout.itemHeight = 50
// layout.scrollDirection = .horizontal
// layout.sectionHeadersPinToVisibleBounds = true
columnWidths = layout.columnWidths
// 初始化UICollectionView
collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.bounces = false
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
collectionView.register(CustomHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: CustomHeader.reuseIdentifier)
collectionView.backgroundColor = .white
self.view.addSubview(collectionView)
}
// UICollectionViewDataSource 必要方法實現(xiàn)
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return columnWidths.count * numberOfRows // 根據(jù)你的需要設(shè)置項數(shù)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = colors.randomElement() // 簡單地交替顏色以便區(qū)分單元格
return cell
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
guard kind == UICollectionView.elementKindSectionHeader else {
return UICollectionReusableView()
}
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: CustomHeader.reuseIdentifier, for: indexPath) as! CustomHeader
header.configure(with: "Section \(indexPath.section)")
return header
}
// UICollectionViewDelegate 方法蚜枢,根據(jù)需要實現(xiàn)
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// 單元格被點擊時的操作
print("Selected cell at \(indexPath)")
// changeLayout()
}
func changeLayout() {
// 創(chuàng)建一個新的布局實例
let newLayout = CustomFlowLayout()
newLayout.columnWidths = [100, 100, 200, 100, 100] // 設(shè)置新的列寬
newLayout.numberOfRows = numberOfRows
newLayout.itemHeight = 50
columnWidths = newLayout.columnWidths
// 無動畫地更新布局
collectionView.setCollectionViewLayout(newLayout, animated: false)
// 如果你希望有動畫效果,可以設(shè)置 animated 為 true
// collectionView.setCollectionViewLayout(newLayout, animated: true)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let layout = collectionView.collectionViewLayout as? CustomFlowLayout else { return }
if scrollView.contentOffset.x != layout.stickyHeaderXOffset {
layout.invalidateLayout()
}
}
}
class CustomFlowLayout: UICollectionViewLayout {
private var cache = [UICollectionViewLayoutAttributes]()
private var headersCache = [Int: UICollectionViewLayoutAttributes]() // Header cache
var stickyHeaderXOffset: CGFloat = 0 // 用于保存固定 header 的 X 偏移量
var columnWidths: [CGFloat] = [] // 每列的寬度
var numberOfRows = 20
var itemHeight: CGFloat = 50
var headerWidth: CGFloat = 50 // Header 的寬度
var totalHeight: CGFloat {
itemHeight * CGFloat(numberOfRows)
}
override var collectionViewContentSize: CGSize {
let width = columnWidths.reduce(0, +) // 所有列寬度之和
let height = totalHeight // 總高度不包括 header
return CGSize(width: width + headerWidth, height: height)
}
override func prepare() {
guard let collectionView = collectionView else { return }
// cache.removeAll()
// headersCache.removeAll()
// 計算 header 的位置
stickyHeaderXOffset = collectionView.contentOffset.x
// 其他 cell 的布局計算
// 確保不重復(fù)添加 header 的布局屬性
if headersCache.isEmpty {
let headerAttributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, with: IndexPath(item: 0, section: 0))
headerAttributes.frame = CGRect(x: stickyHeaderXOffset, y: 0, width: headerWidth, height: totalHeight)
headerAttributes.zIndex = 1024
headersCache[0] = headerAttributes
} else {
// 只更新 X 位置
if let headerAttributes = headersCache[0] {
headerAttributes.frame.origin.x = stickyHeaderXOffset
}
}
// var xOffset: CGFloat = headerWidth + collectionView.contentOffset.x // 開始布局 cell 的 x 偏移量
var yOffset: CGFloat = 0 // y 偏移量
guard cache.isEmpty else { return }
for item in 0..<collectionView.numberOfItems(inSection: 0) {
let column = item % columnWidths.count
let indexPath = IndexPath(item: item, section: 0)
let xOffset = columnWidths[0..<column].reduce(headerWidth, +) + collectionView.contentOffset.x
let frame = CGRect(x: xOffset, y: yOffset, width: columnWidths[column], height: itemHeight)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = frame
cache.append(attributes)
yOffset += (item + 1) % columnWidths.count == 0 ? itemHeight : 0
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
// Add header attributes if in the rect
if let headerAttributes = headersCache[0], rect.intersects(headerAttributes.frame) {
visibleLayoutAttributes.append(headerAttributes)
}
// Add cell attributes if they intersect with the rect
visibleLayoutAttributes.append(contentsOf: cache.filter { attributes in
rect.intersects(attributes.frame)
})
return visibleLayoutAttributes
}
override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return headersCache[indexPath.section]
}
}
class CustomHeader: UICollectionReusableView {
static let reuseIdentifier = "CustomHeader"
private let titleLabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .black
setupViews()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupViews()
}
private func setupViews() {
titleLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(titleLabel)
titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10).isActive = true
titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 10).isActive = true
titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10).isActive = true
backgroundColor = .lightGray // Set the background color for the header
}
func configure(with title: String) {
titleLabel.text = title
}
}
可以左右滑動的collectionView
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來客冈,“玉大人旭从,你說我怎么就攤上這事〕≈伲” “怎么了和悦?”我有些...
- 文/不壞的土叔 我叫張陵,是天一觀的道長渠缕。 經(jīng)常有香客問我鸽素,道長,這世上最難降的妖魔是什么亦鳞? 我笑而不...
- 正文 為了忘掉前任馍忽,我火速辦了婚禮,結(jié)果婚禮上燕差,老公的妹妹穿的比我還像新娘遭笋。我一直安慰自己,他們只是感情好谁不,可當(dāng)我...
- 文/花漫 我一把揭開白布坐梯。 她就那樣靜靜地躺著,像睡著了一般刹帕。 火紅的嫁衣襯著肌膚如雪吵血。 梳的紋絲不亂的頭發(fā)上,一...
- 文/蒼蘭香墨 我猛地睜開眼褒傅,長吁一口氣:“原來是場噩夢啊……” “哼弃锐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起殿托,我...
- 正文 年R本政府宣布测蹲,位于F島的核電站莹捡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏扣甲。R本人自食惡果不足惜篮赢,卻給世界環(huán)境...
- 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琉挖。 院中可真熱鬧启泣,春花似錦、人聲如沸示辈。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽矾麻。三九已至纱耻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間险耀,已是汗流浹背弄喘。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- 這里就是對UICollectionView的一個個人總結(jié),不喜勿噴波桩,如有不妥之處旱幼,望請指正?????? 1.簡介 UIC...
- UICollectionViewFlowLayout類是一個具體的布局對象,它將一個個部件組織成一個可分組的(每個...
- CollectioniOS聚合了項目搭建的一些基本模塊匀油,節(jié)約開發(fā)者時間缘缚,協(xié)助項目的快速搭建,能夠滿足一個項目的基本...
- iOS流布局UICollectionView系列一——初識與簡單使用UICollectionView 一、簡介 U...