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]()
将 UICollectionView
的 allowsSelection
属性 设置为 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
}
}
现在,您不需要 didSelectItemAt
或 didDeselectItemAt
中的任何“单元格外观”代码...集合视图将管理所选状态。
这是一个快速、完整的示例...
自定义单元格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()
}}
}
}
}
我在集合视图中使用方法“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]()
将 UICollectionView
的 allowsSelection
属性 设置为 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
}
}
现在,您不需要 didSelectItemAt
或 didDeselectItemAt
中的任何“单元格外观”代码...集合视图将管理所选状态。
这是一个快速、完整的示例...
自定义单元格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()
}}
}
}
}