我在玩 collectionViews,
尝试为图像布局创建自定义设计。
见下文:
我做到了。
我知道代码不是最漂亮或最规则的,但是我很想知道这是否可行。
当我滚动时,单元格被推到屏幕底部,不再可见。
有解决办法吗?
滚动后的结果vvv
这里是代码:可以复制到空白项目中,自己运行测试。
任何输入将不胜感激。
谢谢
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
var spiralNumber = 0
var collectionView: UICollectionView!
let colors = [UIColor.yellow, UIColor.red, UIColor.blue, UIColor.green, UIColor.purple, UIColor.systemRed, UIColor.systemMint, UIColor.systemBlue, UIColor.cyan, UIColor.gray, UIColor.systemTeal, UIColor.systemYellow]///testing purposes
func generateRandomNumber(min: Int, max: Int) -> Int {
return Int.random(in: min...max)
}//testing purposes
func subtractionFive(number: Int) -> Int {
let largestMultipleOfFive = (number / 5) * 5
return number - largestMultipleOfFive
}
override func viewDidLoad() {
super.viewDidLoad()
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = -(view.frame.width * 2/3) / 2
layout.sectionInset = .zero
collectionView = UICollectionView(frame: view.frame, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
collectionView.backgroundColor = .white
view.addSubview(collectionView)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 300
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
let randomNumber = generateRandomNumber(min: 0, max: colors.count-1)
let randomColor = colors[randomNumber]
cell.backgroundColor = randomColor
let spiralIndex = subtractionFive(number: indexPath.row)
spiralNumber = spiralIndex
let rowHeight = collectionView.frame.width
let rowNumber = CGFloat((indexPath.row/5))
let rowOffset = rowNumber*rowHeight
print("rowNumber-->", Int(rowNumber), rowOffset, rowOffset/rowNumber, spiralNumber)
if spiralNumber == 0 {
cell.frame = CGRect(x: 0, y: 0+rowOffset, width: cell.frame.width, height: cell.frame.height)
}else if spiralNumber == 1{
cell.frame = CGRect(x: cell.frame.width*2, y: 0+rowOffset, width: cell.frame.width, height: cell.frame.height)
}else if spiralNumber == 2{
cell.frame = CGRect(x: 0, y: (cell.frame.height/2)+rowOffset, width: cell.frame.width, height: cell.frame.height)
} else if spiralNumber == 3 {
cell.frame = CGRect(x: cell.frame.width, y: cell.frame.height+rowOffset, width: cell.frame.width, height: cell.frame.height)
} else if spiralNumber == 4{
cell.frame = CGRect(x: cell.frame.width/2, y: (cell.frame.height*2)+rowOffset, width: cell.frame.width, height: cell.frame.height)
}else{
cell.frame = CGRect(x: cell.frame.width, y: (cell.frame.height*2)+rowOffset, width: cell.frame.width, height: cell.frame.height)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width
let spiralIndex = subtractionFive(number: indexPath.row)
spiralNumber = spiralIndex
if spiralNumber == 0 || spiralNumber == 4{
return CGSize(width: width * 2/3, height: width * 1/3)
}else if spiralNumber == 1 || spiralNumber == 2{
return CGSize(width: width * 1/3, height: width * 2/3)
}else if spiralNumber == 3{
return CGSize(width: width * 1/3, height: width * 1/3)
}else{
return CGSize(width: width * 2/3, height: width * 1/3)
}
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
print("test->", indexPath.row/5)
}
}
我原以为当我向下滚动时,单元格会保留在原位。 IE。 collectionView 的正常行为。
首先注意不要在此功能中进行任何调整
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
所有调整大小都应该在这里
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath)
Second Collection view 不知道如何在其中绘制单元格,所以它需要一个布局,所以苹果为我们提供了一个名为 UICollectionViewFlowLayout 的默认布局。你实现 sizeForItemAt 函数来告诉布局你想要的每个单元格的大小但是它是有限的所以当你想做你的例子你需要忽略默认布局并创建你自己的自定义布局这里是最终代码
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
var spiralNumber = 0
var collectionView: UICollectionView!
let colors = [UIColor.yellow, UIColor.red, UIColor.blue, UIColor.green, UIColor.purple, UIColor.systemRed, UIColor.systemMint, UIColor.systemBlue, UIColor.cyan, UIColor.gray, UIColor.systemTeal, UIColor.systemYellow]///testing purposes
func generateRandomNumber(min: Int, max: Int) -> Int {
return Int.random(in: min...max)
}//testing purposes
func subtractionFive(number: Int) -> Int {
let largestMultipleOfFive = (number / 5) * 5
return number - largestMultipleOfFive
}
override func viewDidLoad() {
super.viewDidLoad()
let layout = CustomCollectionViewLayout()
collectionView = UICollectionView(frame: view.frame, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
collectionView.backgroundColor = .white
view.addSubview(collectionView)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 300
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
let randomNumber = generateRandomNumber(min: 0, max: colors.count-1)
let randomColor = colors[randomNumber]
cell.backgroundColor = randomColor
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
// print("test->", indexPath.row/5)
}
}
class CustomCollectionViewLayout: UICollectionViewLayout {
private var cachedAttributes: [UICollectionViewLayoutAttributes] = []
private var contentHeight:CGFloat = 0
var spiralNumber = 0
private var contentWidth: CGFloat {
guard let collectionView = collectionView else {
return 0
}
let insets = collectionView.contentInset
return collectionView.bounds.width - (insets.left + insets.right)
}
override var collectionViewContentSize: CGSize {
return CGSize(width: contentWidth, height: contentHeight)
}
func subtractionFive(number: Int) -> Int {
let largestMultipleOfFive = (number / 5) * 5
return number - largestMultipleOfFive
}
override func prepare() {
guard cachedAttributes.isEmpty, let collectionView else {return}
for index in 0..<collectionView.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: index, section: 0)
let spiralIndex = subtractionFive(number: indexPath.row)
spiralNumber = spiralIndex
let rowHeight = contentWidth
let rowNumber = CGFloat((indexPath.row/5))
let rowOffset = rowNumber*rowHeight
let width = contentWidth
spiralNumber = spiralIndex
var size: CGSize = .zero
if spiralNumber == 0 || spiralNumber == 4{
size = CGSize(width: width * 2/3, height: width * 1/3)
}else if spiralNumber == 1 || spiralNumber == 2{
size = CGSize(width: width * 1/3, height: width * 2/3)
}else if spiralNumber == 3{
size = CGSize(width: width * 1/3, height: width * 1/3)
}else{
size = CGSize(width: width * 2/3, height: width * 1/3)
}
var frame:CGRect = .zero
if spiralNumber == 0 {
frame = CGRect(x: 0, y: 0+rowOffset, width: size.width, height: size.height)
}else if spiralNumber == 1{
frame = CGRect(x: size.width*2, y: 0+rowOffset, width: size.width, height: size.height)
}else if spiralNumber == 2{
frame = CGRect(x: 0, y: (size.height/2)+rowOffset, width: size.width, height: size.height)
} else if spiralNumber == 3 {
frame = CGRect(x: size.width, y: size.height+rowOffset, width: size.width, height: size.height)
} else if spiralNumber == 4{
frame = CGRect(x: size.width/2, y: (size.height*2)+rowOffset, width: size.width, height: size.height)
}else{
frame = CGRect(x: size.width, y: (size.height*2)+rowOffset, width: size.width, height: size.height)
}
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = frame
cachedAttributes.append(attributes)
contentHeight = max(contentHeight, frame.maxY)
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = []
for attributes in cachedAttributes {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
}
return visibleLayoutAttributes
}
}
最后 如果您想了解更多关于集合视图自定义布局的信息,请查看这个有用的博客 https://www.kodeco.com/4829472-uicollectionview-custom-layout-tutorial-pinterest