如何扩展多个UICollectionViewCells

时间:2017-02-20 02:42:17

标签: ios iphone swift uicollectionview uicollectionviewcell

我正在尝试构建一个collectionView,它可以在取消选择它们后选择/轻击或折叠后展开多个单元格,当单元格保留在屏幕上时一切正常,但是一旦展开的单元格离开屏幕,我得到了意想不到的行为。

例如,如果我选择一个IndexPath 0的单元格,然后向下滚动,点击IndexPath为8的单元格,滚动回IndexPath 0的单元格(它已经折叠),我会点击它并滚动回单元格使用IndexPath 8并再次点击它,它扩展+单元格,IndexPath 10也会扩展。

CollectionView已经以编程方式实现,UICollectionViewCell已经被子类化。

包含UICollectionView的ViewController:

import UIKit

class CollectionViewController: UIViewController {

    // MARK: - Properties
    fileprivate var collectionView: UICollectionView!

    var manipulateIndex: NSIndexPath? {
        didSet {
            collectionView.reloadItems(at: collectionView.indexPathsForSelectedItems!)
        }
    }

    // MARK: - Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()

        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)

        collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "Cell")
        collectionView.backgroundColor = UIColor.white
        self.view.addSubview(collectionView)
    }

}

// MARK: - UICollectionViewDataSource
extension CollectionViewController: UICollectionViewDataSource {

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 13
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CustomCell

        cell.textLabel.text = "\(indexPath.item)"
        cell.backgroundColor = UIColor.orange

        return cell
    }
}

// MARK: - UICollectionViewDelegate
extension CollectionViewController: UICollectionViewDelegate {

    func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
        let cell = collectionView.cellForItem(at: indexPath) as! CustomCell
        cell.expanded = !cell.expanded

        manipulateIndex = indexPath as NSIndexPath

        return false
    }
}

// MARK: - UICollectionViewDelegateFlowLayout
extension CollectionViewController: UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        if let cell = collectionView.cellForItem(at: indexPath) as? CustomCell {
            if cell.expanded == true {
                return CGSize(width: self.view.bounds.width - 20, height: 300)
            }

            if cell.expanded == false {
                return CGSize(width: self.view.bounds.width - 20, height: 120.0)
            }
        }

        return CGSize(width: self.view.bounds.width - 20, height: 120.0)

    }
}

子类自定义UICollectionViewCell:

import UIKit

class CustomCell: UICollectionViewCell {

    var expanded: Bool = false
    var textLabel: UILabel!

    override init(frame: CGRect) {
        super.init(frame: frame)

        textLabel = UILabel(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height/3))
        textLabel.font = UIFont.systemFont(ofSize: UIFont.smallSystemFontSize)
        textLabel.textAlignment = .center
        contentView.addSubview(textLabel)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

请帮助并非常感谢那位能帮助我的人! :)

2 个答案:

答案 0 :(得分:2)

试试这个:
示例1:一次只展开一个单元格
注意:无需在自定义单元格中使用扩展的bool变量

var section:Int?
var preSection:Int?
var expand:Bool = false


extension ViewController: UICollectionViewDataSource {

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 13
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CustomCell

        cell.textLabel.text = "\(indexPath.item)"
        cell.backgroundColor = UIColor.orange

        return cell
    }
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        if (self.section != nil) {
            self.preSection = self.section
        }

        self.section = indexPath.row

        if self.preSection == self.section {
            self.preSection = nil
            self.section = nil
        }else if (self.preSection != nil) {
            self.expand = false
        }
        self.expand = !self.expand
        self.collectionView.reloadItems(at: collectionView.indexPathsForSelectedItems!)

    }

}


// MARK: - UICollectionViewDelegateFlowLayout
extension ViewController: UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        if self.expand, let row = self.section, row == indexPath.row {
            return CGSize(width: self.view.bounds.width - 20, height: 300)
        }else{
            return CGSize(width: self.view.bounds.width - 20, height: 120.0)
        }

    }
}

示例2: 展开多个单元格

import UIKit

class ViewController: UIViewController {


    // MARK: - Properties
    fileprivate var collectionView: UICollectionView!
    var expandSection = [Bool]()
    var items = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.items = ["A","B","C","D","E","F","G","H","J","K"]
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)

        collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "Cell")
        collectionView.backgroundColor = UIColor.white
        self.expandSection = [Bool](repeating: false, count: self.items.count)

        self.view.addSubview(collectionView)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

extension ViewController: UICollectionViewDataSource {

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.items.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CustomCell

        cell.textLabel.text = self.items[indexPath.row]
        cell.backgroundColor = UIColor.orange

        return cell
    }
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        self.expandSection[indexPath.row] = !self.expandSection[indexPath.row]
        self.collectionView.reloadItems(at: collectionView.indexPathsForSelectedItems!)
    }

}


// MARK: - UICollectionViewDelegateFlowLayout
extension ViewController: UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

        if self.expandSection[indexPath.row] {
            return CGSize(width: self.view.bounds.width - 20, height: 300)
        }else{
            return CGSize(width: self.view.bounds.width - 20, height: 120.0)
        }
    }
}

答案 1 :(得分:0)

UICollectionView会将您的单元格重用于数据模型中的多个对象。在reloadItems期间,您无法控制哪些单元格被重用。您不应该假设给定单元格中的expanded状态对应于数据模型的状态。相反,您应该在数据模型中以某种方式保持expanded状态,并在每次调用cellForItemAt时重新设置该状态。

换句话说,在模型中保持状态并在cellForItemAt中设置单元格状态,不要将其保存在单元格中。