UICollectionView - 选择所有单元格无法正确更新

时间:2017-07-09 23:39:48

标签: ios swift uicollectionview

我有一个按钮,可以选择集合视图中的所有单元格。单击后,按钮功能会发生变化,以便在再次按下时取消选中所有单元格。

到目前为止很好......但是 1)当您使用按钮选择所有单元格时,向下滚动一点并再次向上滚动 2)然后用按钮取消选择所有单元格,再次用按钮选择所有单元格 3)然后开始向下滚动,一些单元格(大多数1-2个完整行,后面的单元格再次正常)未正确更新,因此它们出现在所选状态,即不同的背景颜色。看起来像dequeueReusableCell的问题,但我无法绕过它...

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {    
    if cell.isSelected {
        cell.backgroundColor = UIColor.green
    } else {
        cell.backgroundColor = UIColor.white
    }

    if cell.viewWithTag(1) != nil {
        let cellTitle = cell.viewWithTag(1) as! UILabel
        cellTitle.text = String(indexPath.row)
    }
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    if let cell = collectionView.cellForItem(at: indexPath) {
        cell.backgroundColor = UIColor.green

        selectedCells.append(indexPath.row)
    }
}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    if let cell = collectionView.cellForItem(at: indexPath) {
        cell.backgroundColor = UIColor.white

        selectedCells.removeObject(indexPath.row)
    }
}

处理按钮点击的操作方法

@IBAction func selectButtonTapped(_ sender: Any) {
    if isSelectAllActive {
        // Deselect all cells
        selectedCells.removeAll()

        for indexPath: IndexPath in collectionView!.indexPathsForSelectedItems! {
            collectionView!.deselectItem(at: indexPath, animated: false)
            collectionView(collectionView!, didDeselectItemAt: indexPath)

            let cell: UICollectionViewCell
            cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CVCell", for: indexPath)
        }

        selectButton.title = "Select all"
        isSelectAllActive = false
    } else {
        // Select all cells
        for i in 0 ..< collectionView!.numberOfItems(inSection: 0) {
            collectionView!.selectItem(at: IndexPath(item: i, section: 0), animated: false, scrollPosition: UICollectionViewScrollPosition())
            collectionView(collectionView!, didSelectItemAt: IndexPath(item: i, section: 0))
        }

        selectedCells.removeAll()

        let indexPaths: [IndexPath] = collectionView.indexPathsForSelectedItems!
        for item in indexPaths {
            selectedCells.append(item.row)
        }
        selectedCells.sort{$0 < $1}

        selectButton.title = "Select none"
        isSelectAllActive = true
    }
}

完成删除对象的数组扩展

extension Array where Element : Equatable {
    mutating func removeObject(_ object : Iterator.Element) {
        if let index = self.index(of: object) {
            self.remove(at: index)
        }
    }
}

完整的Xcode项目可以在这里找到:https://www.dropbox.com/s/uaj1asg43z7bl2a/SelectAllCells.zip
使用Xcode 9.0 beta 1,iOS11 Simulator / iPhone SE

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

您的代码有点混乱,因为您试图在数组和单元格本身中跟踪单元格选择状态。

我只使用Set<IndexPath>因为它比数组更简单,更有效。然后,您可以在cellForItemAt:中返回单元格时引用此集,并且您不需要在willDisplay中执行任何操作。

当您选择/取消选择全部时,您可以重新加载整个集合视图,当选择/取消选择单个单元格时,只需重新加载该单元格。

@objcMembers
class MainViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

    @IBOutlet var collectionView: UICollectionView!
    @IBOutlet var toolBar: UIToolbar?
    @IBOutlet weak var selectButton: UIBarButtonItem!

    var selectedCells = Set<IndexPath>()
    var isSelectAllActive = false

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

        // Collection view
        collectionView!.delegate = self
        collectionView!.dataSource = self
        collectionView!.allowsMultipleSelection = true
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    }

    @IBAction func selectButtonTapped(_ sender: Any) {
        if isSelectAllActive {
            // Deselect all cells
            selectedCells.removeAll()

            selectButton.title = "Select all"
            isSelectAllActive = false
        } else {
            // Select all cells
            for i in 0 ..< collectionView!.numberOfItems(inSection: 0) {
                self.selectedCells.insert(IndexPath(item:i, section:0))
            }

            selectButton.title = "Select none"
            isSelectAllActive = true
        }
        self.collectionView.reloadData()
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell: UICollectionViewCell
        cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CVCell", for: indexPath)
        if self.selectedCells.contains(indexPath) {
            cell.backgroundColor = .green
        } else {
            cell.backgroundColor = .white
        }
        if cell.viewWithTag(1) != nil {
            let cellTitle = cell.viewWithTag(1) as! UILabel
            cellTitle.text = String(indexPath.row)
        }
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("\ndidSelectItemAt: \(indexPath.row)")
        if selectedCells.contains(indexPath) {
            selectedCells.remove(indexPath)
        } else {
            selectedCells.insert(indexPath)
        }
           self.collectionView.deselectItem(at: indexPath, animated: false)
        self.collectionView.reloadItems(at: [indexPath])

        print("selectedCells: \(selectedCells)")
    }
}