创建覆盖单元格的自定义 collectionView

问题描述 投票:0回答:1

我在玩 collectionViews,
尝试为图像布局创建自定义设计。
见下文:

我做到了。
我知道代码不是最漂亮或最规则的,但是我很想知道这是否可行。
当我滚动时,单元格被推到屏幕底部,不再可见。

有解决办法吗?

滚动后的结果vvv

enter image description here

这里是代码:可以复制到空白项目中,自己运行测试。

任何输入将不胜感激。

谢谢

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 的正常行为。

ios swift scroll uicollectionview
1个回答
0
投票

首先注意不要在此功能中进行任何调整

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

© www.soinside.com 2019 - 2024. All rights reserved.