如果从 UICollectionView 的其他部分中选择了一个单元格,则取消选择所有其他选择

Posted

技术标签:

【中文标题】如果从 UICollectionView 的其他部分中选择了一个单元格,则取消选择所有其他选择【英文标题】:Deselect all other selections if one cell selected from other section in UICollectionView 【发布时间】:2016-12-29 13:02:28 【问题描述】:

如果从第 1 节中选择了任何单元格,如何取消选择第 0 节中 UICollectionView 中的所有其他选定单元格。 以下是我到目前为止尝试过的:

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)

    let cell = collectionView.cellForItemAtIndexPath(indexPath) as! SignupStep3CollectionViewCell

    cell.layer.borderWidth = 4
    cell.layer.masksToBounds = false
    cell.layer.borderColor = UIColor.init(red: 46.0/255.0, green: 234.0/255.0, blue: 219.0/255.0, alpha: 1.0).CGColor
    cell.layer.cornerRadius = cell.frame.height/2
    cell.clipsToBounds = true

    if indexPath.section == 1
    
        collectionView.selectItemAtIndexPath(nil, animated: true, scrollPosition: .None)
    

这不起作用,请指导。

【问题讨论】:

【参考方案1】:

试试这个。

斯威夫特 3

func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool 

    //multiple selection in section 0 otherwise single selection in other section
    if indexPath.section == 0 
        return true
    
    let indexPaths = collectionView.indexPathsForSelectedItems
    if (indexPaths?.count) ?? 0 > 0 

        /// If you need simple way
        for index in indexPaths! 
        if index.section == indexPath.section 
            self.collectionView.deselectItem(at: index, animated: true) // if want deselect previous selection
            //return false  //if you do not want further selection
            
        

        /// If you need some optimization and don't want to run loop each time
        /*
        let arrIndexPaths = NSArray(array: indexPaths!)
        let sectionPrediate = NSPredicate(format: "section == %d", indexPath.section)
        let arrSelections = arrIndexPaths.filtered(using: sectionPrediate) as? [IndexPath]
        if arrSelections?.count ?? 0 > 0 
            self.collectionView.deselectItem(at: arrSelections![0], animated: true) // if want deselect previous selection
            //return false  //if you do not want further selection
        */
    

    return true

斯威夫特 2.3

func collectionView(collectionView: UICollectionView, shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool 
    //multiple selection in section 0 otherwise single selection in other section
    if indexPath.section == 0 
        return true
    
    let indexPaths = collectionView.indexPathsForSelectedItems()
    if (indexPaths?.count) ?? 0 > 0 

        /// If you need simple way
        for index in indexPaths! 
            if index.section == indexPath.section 
                self.colletionView.deselectItemAtIndexPath(index, animated: true) // if want deselect previous selection
                //return false  //if you do not want further selection
            
        

        /// If you need some optimization and don't want to run loop each time
        /*let arrIndexPaths = NSArray(array: indexPaths!)
        let sectionPrediate = NSPredicate(format: "section == %d", indexPath.section)
        let arrSelections = arrIndexPaths.filteredArrayUsingPredicate(sectionPrediate) as? [NSIndexPath]
        if arrSelections?.count ?? 0 > 0 
            self.colletionView.deselectItemAtIndexPath(arrSelections![0], animated: true) // if want deselect previous selection
            //return false  //if you do not want further selection
        */
    

    return true

【讨论】:

“NSIndexpath 不符合协议序列类型”错误来了 你在使用 Swift3 吗?因为这适用于 Xcode 8.1 好的,然后尝试在 swift 2 中转换我的代码。我认为它会对您有所帮助... 能否请您写在 swift 2 中不知道 swift 3? 这个逻辑我现在已经实现了,并且在选择第 1 项时还设法清除所有选择。现在面临的问题是滚动选择错误。似乎是双端队列可重用性的问题。请指导一下?【参考方案2】:

您可以实现以下委托方法

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 
   let section = indexPath.section
    let selectedRows = collectionView.indexPathsForSelectedItems
    for i in 0...(selectedRows!.count - 1) 
        let path = selectedRows![i] as IndexPath
        if(path.section != section) 
            collectionView.deselectItem(at: path, animated: false)
        
    

在选择任何特定项目时,您可以获得所有选定的项目。然后取消选择来自不同部分的所有项目。

【讨论】:

“NSIndexpath 不符合协议序列类型”错误来了 更新了答案。你现在可以检查吗? 能否请您写在 swift 2 中不知道 swift 3?【参考方案3】:

基于 Mrugesh 的回答,但也考虑到第 1 节要求中的单一选择:

斯威夫特 2:

func collectionView(collectionView: UICollectionView, shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool 
    let indexPaths = collectionView.indexPathsForSelectedItems()
    if indexPaths?.count ?? 0 > 0 
        if indexPaths![0].section != indexPath.section || indexPath.section == 1 
            for index in indexPaths! 
                collectionView.deselectItemAtIndexPath(index, animated: true)
            
        
    
    return true

斯威夫特 3:

func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool 
    let indexPaths = collectionView.indexPathsForSelectedItems
    if (indexPaths?.count) ?? 0 > 0 
        if indexPaths![0].section != indexPath.section || indexPath.section == 1 
            for index in indexPaths! 
                collectionView.deselectItem(at: index, animated: true)
            
        
    
    return true

根据你的视图控制器是UICollectionViewController的子类还是仅仅实现了它的委托和数据源协议,你可能需要override这个函数。

【讨论】:

它只允许我启用第 0 节多选和第 1 节单选。但如果选择了第 1 节中的任何单元格,则不会清除第 0 节的选择。 这很奇怪。它适用于一个带有集合视图的简单应用程序,使用cell.selected 来确定单元格应具有的背景颜色。 indexPathsForSelectedItems 也会打印正确的选择。我不能同时选择第 0 节和第 1 节。您如何确定选择的内容?【参考方案4】:

使用下面的代码来解决问题:- 清除第 1 节的点击单元格上的第 0 节选择。 // didSelect 方法

 let indexSet = NSIndexSet(index: 1)
        self.collectionViewBrands.reloadSections(indexSet)

【讨论】:

以上是关于如果从 UICollectionView 的其他部分中选择了一个单元格,则取消选择所有其他选择的主要内容,如果未能解决你的问题,请参考以下文章

如果从 UICollectionView 的其他部分中选择了一个单元格,则取消选择所有其他选择

UICollectionView 最初滚动跳跃

将 UICollectionView 滚动到底部

UICollectionView 滚动到底部不显示整个项目

UICollectionview:滚动到顶部时安全区域上的灰色条

如何通过CollectionView中的Flow Layout将单元格对齐到顶部