CollectionView 方法 didDeselectItemAt 不起作用

CollectionView method didDeselectItemAt not work

我在集合视图中使用方法“didDeselectItemAt”时遇到问题。 应用程序:我有一个包含单元格的集合(见屏幕截图)。用户只能突出显示一个单元格。

当用户单击一个单元格时,它会突出显示。当他点击另一个时,另一个selected,而前一个变得正常。

并且当我 select 时,例如,第一个单元格,然后是最后一个单元格,第一个保持 selected。 根据经验,我发现了这个问题。发生在第一个之后,我在单击第一个单元格时单击了一个不在视图中的单元格(您需要滚动)

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    if collectionView == albumsCollectionView {
        guard let cell = collectionView.cellForItem(at: indexPath) as? AlbumCollectionCell else { return }
        cell.isCellSelected()
        presenter?.didChooseAlbum(with: indexPath.row) {
            self.picturesCollectionView.reloadData()
        }}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    if collectionView == albumsCollectionView {
        guard let cell = collectionView.cellForItem(at: indexPath) as? AlbumCollectionCell else { return }
        cell.isCellDeselected()
    }
}

正如@DonMag 在评论中提到的,您必须跟踪数据源中的选定状态。以下是步骤。

当您在单元格中显示一些数据时,您可以为其制作模型。

struct Album {
    let name: String
    var isSelected: Bool
}

AlbumCollectionCell中添加Album类型变量。并覆盖 UICollectionViewCell

isSelected 属性
class AlbumCollectionCell: UICollectionViewCell {

    var album: Album? {
        didSet {
            guard let album = album else { return }

            if shoe.isSelected {
                self.backgroundColor = UIColor.orange
            }
            else {
                self.backgroundColor = UIColor.green
            }
            
           self.albumLabel.textColor = .white
           self.albumLabel.text = album.name
        }
    }
    
    override var isSelected: Bool {
        didSet {
            if self.isSelected {
                self.backgroundColor = UIColor.orange
            }
            else {
                self.backgroundColor = UIColor.green
            }
        }
    }
}

UIViewController中,创建一个Album类型的数组来保存单元格的数据。您可以在 viewDidLoad() 方法中分配数据。

var albums = [Album]()

UICollectionViewallowsSelection 属性 设置为 true

collectionView.allowsSelection = true

cellForItem 方法中将 Album 数据传递给单元格。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AlbumCollectionCell", for: indexPath) as? AlbumCollectionCell {
        cell.album = albums[indexPath.item]
        return cell
    }
    return UICollectionViewCell()
}

修改 didSelectItem 方法如下。

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    albums[indexPath.item].isSelected = true
}

并覆盖 didDeselectItemAt 方法。

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    albums[indexPath.item].isSelected = false
}

如果您尝试保留 选择 - 也就是说,如果您想要保存它并恢复上次应用程序使用之间的选择,或者如果您要离开并且您想在再次导航到该控制器时恢复它 - 然后您需要使用您的数据源跟踪它。

但是,如果您不关心持久性,可以让集合视图处理它。

在您的单元格 class 中,覆盖 isSelected:

override var isSelected: Bool {
    didSet {
        contentView.backgroundColor = isSelected ? .systemOrange : .systemGreen
    }
}

现在,您不需要 didSelectItemAtdidDeselectItemAt 中的任何“单元格外观”代码...集合视图将管理所选状态。

这是一个快速、完整的示例...

自定义单元格class

class LabelCollectionViewCell: UICollectionViewCell {
    let label = UILabel()
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        label.textColor = .white
        label.textAlignment = .center
        label.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(label)
        let g = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            label.topAnchor.constraint(equalTo: g.topAnchor, constant: 4.0),
            label.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
            label.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
            label.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -4.0),
        ])
        contentView.backgroundColor = .systemGreen
        contentView.layer.cornerRadius = 12
    }
    override var isSelected: Bool {
        didSet {
            contentView.backgroundColor = isSelected ? .systemOrange : .systemGreen
        }
    }
}

示例控制器class

class SelColViewVC: UIViewController {
    
    var albumsCollectionView: UICollectionView!
    
    let myData: [String] = [
        "Favorites",
        "Recents",
        "Recently Added",
        "Something Else",
        "Five",
        "Six",
        "Seven",
        "Eight",
    ]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let fl = UICollectionViewFlowLayout()
        fl.scrollDirection = .horizontal
        fl.estimatedItemSize = CGSize(width: 120, height: 50)
        albumsCollectionView = UICollectionView(frame: .zero, collectionViewLayout: fl)
        albumsCollectionView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(albumsCollectionView)
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            albumsCollectionView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            albumsCollectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            albumsCollectionView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            albumsCollectionView.heightAnchor.constraint(equalToConstant: 80.0),
        ])
        
        albumsCollectionView.contentInset = UIEdgeInsets(top: 0.0, left: 8.0, bottom: 0.0, right: 8.0)
        albumsCollectionView.register(LabelCollectionViewCell.self, forCellWithReuseIdentifier: "cell")
        albumsCollectionView.dataSource = self
        albumsCollectionView.delegate = self
        
    }
    
}
extension SelColViewVC: UICollectionViewDataSource, UICollectionViewDelegate {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return myData.count
    }
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let c = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! LabelCollectionViewCell
        c.label.text = myData[indexPath.item]
        return c
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if collectionView == albumsCollectionView {
            presenter?.didChooseAlbum(with: indexPath.item) {
                self.picturesCollectionView.reloadData()
            }}
        }
    }
}