在第二次点击时取消选择 UICollectionView 单元格

Posted

技术标签:

【中文标题】在第二次点击时取消选择 UICollectionView 单元格【英文标题】:Deselect UICollectionView cell on second tap 【发布时间】:2017-12-13 13:54:18 【问题描述】:

我的项目应用程序中有 tableViews 和 collectionViews。在表格和集合中,我希望在第一次点击时选择行/单元格,并在第二次点击时取消选择。

通过tableView,我找到了一个相当简单明了的解决方案here,效果很好。

另一方面,CollectionView 被证明是完全不同类型的野兽。与 tableView 不同的是,没有willSelectItemAt 委托方法,因此无法在第二次点击注册之前检查项目是否处于选中状态。实现 shouldDeselectItemAtdidDeselectItemAt 不会产生任何结果 - 这些方法永远不会在点击时已被选中的单元格上调用。

唯一可行的solution 建议为每个collectionView 单元格创建一个UIButton,但它真的应该那么复杂吗?

【问题讨论】:

【参考方案1】:

尝试使用“shouldSelectItem”UIColllectionViewDelegate 方法。

func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool 
    let item = collectionView.cellForItem(at: indexPath)
    if item?.isSelected ?? false 
        collectionView.deselectItem(at: indexPath, animated: true)
     else 
        collectionView.selectItem(at: indexPath, animated: true, scrollPosition: [])
        return true
    

    return false

【讨论】:

谢谢,很好的解决方案!对于else 语句,我使用return true 而不是selectItem(),因为我需要在didSelectItemAt() 方法中完成一些逻辑,现在它可以按预期完成工作)【参考方案2】:

@pkorosecanswer 的较短版本,具有完全相同的效果,如下所示:

override func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool 
    if collectionView.cellForItem(at: indexPath)?.isSelected ?? false 
        collectionView.deselectItem(at: indexPath, animated: true)
        return false
    
    return true

@Manav 建议的替代方法是:

override func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool 
    if collectionView.indexPathsForSelectedItems?.contains(indexPath) ?? false 
        collectionView.deselectItem(at: indexPath, animated: true)
        return false
    
    return true

【讨论】:

谢谢。这是另一种情况,如果不想向集合视图询问单元格:collectionView.indexPathsForSelectedItems?.contains(indexPath) == true【参考方案3】:

我个人认为更简洁的另一个选项是允许在集合视图上进行多项选择,然后在下一次选择之前手动取消选择当前选择的项目。

第一步:允许多选

override func viewDidLoad() 
    super.viewDidLoad()
    collectionView.allowsMultipleSelection = true

第二步:手动取消选择之前选择的项目

func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool 
    collectionView.indexPathsForSelectedItems?.forEach  ip in
        collectionView.deselectItem(at: ip, animated: true)
    
    return true

【讨论】:

【参考方案4】:

如果您不想多选,请尝试使用此代码进行取消选择。

var selectedIndex:Int?

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 
    let cell = collectionView.cellForItem(at: indexPath) as! CategoryCollectionViewCell
    if selectedIndex == indexPath.row 
        selectedIndex = nil
        // unselect code here
     else 
        selectedIndex = indexPath.row
        // Select code here
    


func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) 
    // unselect code here

【讨论】:

【参考方案5】:

发布类似的解决方案,但调用委托,以便您保持一切同步,模拟实际取消选择(加上稍微清晰的命名):

func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool 
    let isSelectedAlready = collectionView.indexPathsForSelectedItems?.contains(indexPath)
    if isSelectedAlready == true 
        collectionView.deselectItem(at: indexPath, animated: true)
        collectionView.delegate?.collectionView?(collectionView, didDeselectItemAt: indexPath)
        return false
    
    return true

【讨论】:

以上是关于在第二次点击时取消选择 UICollectionView 单元格的主要内容,如果未能解决你的问题,请参考以下文章

HTML5 日期选择器仅在第二次点击时打开

UIImagePickerController 在第二次取消时崩溃

内联日期选择器在第二次尝试时崩溃

合并 - 订阅者在第二次订阅时被静默取消

Swift 2:电子邮件取消按钮在第二次尝试表视图后停止工作

允许在第二次检查时将单选字段设置为可取消检查