UICollectionView选择和取消选择问题

时间:2013-03-11 03:41:58

标签: ios cocoa-touch uicollectionview

所以我有一个主要对象,它有许多与之关联的图像。图像也是一个对象。

假设您有一个集合视图控制器,并且在该控制器中有

cellForItemAtIndexPath

基于主要对象,如果它具有与之关联的当前图像,我想将selected设置为true。但我希望用户能够随时“取消选择”当前单元格以删除与主对象的关联。

我发现如果你设置“selected to true” - 如果cellForItemAtIndexPath中的主要对象和图像之间存在关系,则取消选择不再是一种选择。

in

didDeselectItemAtIndexPath

didSelectItemAtIndexPath

我用日志测试是否被调用。如果一个单元格被设置为选中 - nether被调用,但如果我从未在cellForItemAtIndexPath中设置一个单元格,我可以选择并取消选择我想要的所有单元格。

这是集合视图应该起作用的预期方式吗?我阅读了文档,似乎并没有谈到这一点。我解释文档意味着它的工作方式与表视图单元格相同。有一些明显的变化

这也表明控制器设置正确并使用适当的委托方法.... hmmmm

15 个答案:

答案 0 :(得分:84)

我有同样的问题,即。在cell.selected = YES中设置[UICollectionView collectionView:cellForItemAtIndexPath:],然后点击它就无法取消选择该单元格。

现在的解决方案:我在[UICollectionViewCell setSelected:]中拨打 [UICollectionView selectItemAtIndexPath:animated:scrollPosition:][UICollectionView collectionView:cellForItemAtIndexPath:]

答案 1 :(得分:45)

我遇到了UICollectionView的取消选择问题,我发现我不允许在collectionView上进行多项选择。因此,当我进行测试时,我总是在同一个单元格上尝试,如果单个选择为ON,则无法取消选择已选择的单元格。

我不得不补充道:

myCollectionView.allowsMultipleSelection = YES;

答案 2 :(得分:43)

您的Cell类中是否有自定义setSelected方法?你在那个方法中调用[super setSelected:selected]吗?

我有一个神秘的问题,我正在使用多项选择,一旦被选中,我就无法取消选择。调用super方法解决了这个问题。

答案 3 :(得分:32)

这有点老了但是,因为我使用swift遇到同样的问题,我会添加我的答案。 使用时:

 collectionView.selectItemAtIndexPath(indexPath, animated: true, scrollPosition: [])

细胞根本没有被选中。但是在使用时:

cell.selected = true

它确实被选中但我无法再选择/取消选择该单元格。

我的解决方案(使用两种方法):

cell.selected = true
collectionView.selectItemAtIndexPath(indexPath, animated: true, scrollPosition: .None)

当调用这两种方法时:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell

它完美无缺!

答案 4 :(得分:10)

UICollectionView相比,我不知道为什么UITableViewController如此混乱...... 我发现了一些事情。

多次调用setSelected:的原因是因为调用了序列方法。该序列与UITextFieldDelegate方法的序列非常相似。

collectionView:shouldSelectItemAtIndexPath:实际选择单元格之前调用方法collectionView,因为它实际上在询问“应该选择它”吗?

实际上在collectionView:didSelectItemAtIndexPath:选择单元格后调用{p> collectionView。因此,名称“确实选择。”

所以这就是你的情况(和我的情况一样,我不得不在这个问题上花费数小时)。

用户再次触摸选定的单元格以取消选择。调用shouldSelectItemAtIndexPath:来检查是否应该选择单元格。 collectionView选择单元格,然后调用didSelectItemAtIndexPath。无论你在这一点做什么都是在单元格的selected属性设置为YES之后。这就是cell.selected = !cell.selected之类的东西无效的原因。

TL; DR - 让collectionView通过调用collectionView:shouldSelectItemAtIndexPath:取消选择代理方法deselectItemAtIndexPath:animated:中的单元格并返回NO

我所做的简短例子:

- (BOOL)collectionView:(OPTXListView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    NSArray *selectedItemIndexPaths = [collectionView indexPathsForSelectedItems];

    if ([selectedItemIndexPaths count]) {
        NSIndexPath *selectedIndexPath = selectedItemIndexPaths[0];

        if ([selectedIndexPath isEqual:indexPath]) {
            [collectionView deselectItemAtIndexPath:indexPath animated:YES];

            return NO;
        } else {
            [collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];

            return YES;
        }
    } else {
        [collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];

        return YES;
    }
}

答案 5 :(得分:7)

这是我对Swift 2.0的回答。

我可以在viewDidLoad()

中设置以下内容
collectionView.allowsMultipleSelection = true;

然后我实现了这些方法

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
    let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCell
    cell.toggleSelected()
}

func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
    let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCell
    cell.toggleSelected()
}

最后

class MyCell : UICollectionViewCell {

    ....

    func toggleSelected ()
    {
        if (selected){
            backgroundColor = UIColor.orangeColor()
        }else {
            backgroundColor = UIColor.whiteColor()
        }
    }

}

答案 6 :(得分:2)

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

    let cell = collectionView.cellForItemAtIndexPath(indexPath)
    if cell?.selected == true{
        cell?.layer.borderWidth = 4.0
         cell?.layer.borderColor = UIColor.greenColor().CGColor
    }   
}func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
    let cell = collectionView.cellForItemAtIndexPath(indexPath)
    if cell?.selected == false{
            cell?.layer.borderColor = UIColor.clearColor().CGColor
    }

}

我发现的简单解决方案

答案 7 :(得分:2)

生活在iOS 9时代,这里有很多东西需要检查。

  1. 检查您是否collectionView.allowsSelection设置为YES
  2. 检查您是否collectionView.allowsMultipleSelection设置为YES(如果您需要此功能)
  3. 现在是粉丝部分。 如果您听取Apple并在backgroundColor上设置cell.contentView而不是cell本身,那么您刚刚隐藏其selectedBackgroundView。这是因为:

    (lldb) po cell.selectedBackgroundView
    <UIView: 0x7fd2dae26bb0; frame = (0 0; 64 49.5); autoresize = W+H; layer = <CALayer: 0x7fd2dae26d20>>
    
    (lldb) po cell.contentView
    <UIView: 0x7fd2dae22690; frame = (0 0; 64 49.5); gestureRecognizers = <NSArray: 0x7fd2dae26500>; layer = <CALayer: 0x7fd2dae1aca0>>
    
    (lldb) pviews cell
    <MyCell: 0x7fd2dae1aa70; baseClass = UICollectionViewCell; frame = (0 0; 64 49.5); clipsToBounds = YES; hidden = YES; opaque = NO; layer = <CALayer: 0x7fd2dae1ac80>>
       | <UIView: 0x7fd2dae26bb0; frame = (0 0; 64 49.5); autoresize = W+H; layer = <CALayer: 0x7fd2dae26d20>>
       | <UIView: 0x7fd2dae22690; frame = (0 0; 64 49.5); gestureRecognizers = <NSArray: 0x7fd2dae26500>; layer = <CALayer: 0x7fd2dae1aca0>>
       |    | <UIView: 0x7fd2dae24a60; frame = (0 0; 64 49.5); clipsToBounds = YES; alpha = 0; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x7fd2dae1acc0>>
       |    | <UILabel: 0x7fd2dae24bd0; frame = (0 0; 64 17.5); text = '1'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fd2dae240c0>>
       |    | <UILabel: 0x7fd2dae25030; frame = (0 21.5; 64 24); text = '1,04'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fd2dae25240>>
    
    (lldb) po cell.contentView.backgroundColor
    UIDeviceRGBColorSpace 0.4 0.4 0.4 1
    

    因此,如果您想使用selectedBackgroundView(使用cell.selectedselectItemAtIndexPath...打开/关闭的那个),请执行以下操作:

    cell.backgroundColor = SOME_COLOR;
    cell.contentView.backgroundColor = [UIColor clearColor];
    

    它应该可以正常工作。

答案 8 :(得分:1)

我不知道我理解了这个问题,但是每个单元格都设置了选定状态,并且包含了单元格中的所有子视图。你没有解释你的意思“主要对象有很多与之相关的图像。”在子视图中关联?或者你究竟是什么样的联想?

这听起来像是一个设计问题。也许你需要一个UIView子类,它包含你需要的任何相关对象;然后可以将该子类设置为内容视图。我这样做,例如,我有一个图像,描述和与图像相关的录音。所有都在子类中定义,然后每个子类成为单个单元格的内容视图。

我还使用相关图像的排列到包含它们的文件夹。在此设置下,文件夹和图像均具有子类,并且其中一个可以作为内容视图附加到单元格(这些作为单个实体存储在核心数据中)。

也许你可以进一步解释你的问题?

答案 9 :(得分:1)

你看过了吗?

- (BOOL)collectionView:(PSTCollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath;

请更清楚地说明您的问题,也许我们可以深入了解它。我刚刚在UICollectionView上花了一些时间。

我认为你的问题可能源于这样的困惑:如果你以编程方式设置cell.selected = YES,那么didSelectItemAtIndexPath:未被调用的原因是因为只有当collectionView本身负责单元格时才会使用#39;选择(例如通过点击)。

答案 10 :(得分:1)

我正在使用自定义单元格子类,对我来说,我只需要在子类中的self.selected = false中设置prepareForReuse()

答案 11 :(得分:1)

这个问题已经六岁了,但是我不在乎;在到达这里并发现没有答案可以解决我的特定问题后,我最终找到了我认为是该问题的最佳答案。因此,我将其张贴在这里以供后代使用。

由于UICollectionView调用该方法的方式,因此在cellForItemAtIndexPath中选择单元格是有问题的。最初设置集合视图时,不仅会调用它。当集合视图滚动时,它被连续调用,因为集合视图仅向其数据源询问可见单元,从而节省了大量开销。

由于集合视图不会将其所有单元格都保留在内存中,因此它们需要管理自己单元格的选定状态。他们不希望您向他们提供已设置isSelected属性的单元格。他们希望您为他们提供单元格,并且将在适当的情况下在其上设置选定的属性。

这就是为什么Apple警告您不要直接设置UICollectionViewCell的isSelected属性。 UICollectionView希望为您解决这个问题。

SO ,答案是尝试在cellForItemAtIndexPath方法中选择单元格。选择要最初选择的单元格的最佳位置是UICollectionViewController的viewWillAppear方法。在该方法中,通过调用UICollectionView.selectItem(at:animated:scrollPosition :)选择所有所需的单元格,然后直接在单元格上选择不要 set 。

答案 12 :(得分:0)

[UICollectionView selectItemAtIndexPath:animated:scrollPosition:]中调用 <{em> [UICollectionView collectionView:cellForItemAtIndexPath:]dispatch_async(dispatch_get_main_queue(), ^{});时无效,请尝试在{{1}}内调用它们 块。

这就是最终为我解决的问题。

答案 13 :(得分:0)

当我这样做时,

Collectionview 选择,取消选择问题已解决。在viewDidLoad中,添加collViewRiskPreferences.allowsMultipleSelection = false并添加以下内容

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier:"MyCell", for: indexPath) as? MyCell else { return UICollectionViewCell() }
        
        cell.setupCellStyle(isSelected: false)
        
        return cell
    }

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        guard let cell = collectionView.cellForItem(at: indexPath) else { return }
        cell.setupCellStyle(isSelected: true)
    }
    
    func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
        guard let cell = collectionView.cellForItem(at: indexPath) else { return }
        cell.setupCellStyle(isSelected: false)
    }

class MyCell: UICollectionViewCell {
        func setupCellStyle(isSelected: Bool) {
            if(isSelected) {
                self.contentView.backgroundColor = UIColor.blue
            } else {
                self.contentView.backgroundColor = UIColor.green
            }
        }
    }

答案 14 :(得分:-1)

最好通过设置backgroundView和选定的背景视图来处理单元格选择和取消选择。我建议确保在layoutSubviews方法中正确设置这两个视图的框架(如果您通过IB设置所选视图和背景视图)。

不要忘记设置您的contentView(如果有的话)背景颜色,以便显示正确的背景视图。

不要直接设置单元格的选择(即通过cell.selected = YES),在集合视图中使用为此目的设计的方法。文件清楚地解释了这一点,但我同意这些信息在指南中有些分散。

您不需要直接在collectionView数据源中查看单元格的背景颜色。

另外,作为最后一点,如果要在单元格的类中实现这些,请不要忘记调用[super prepareForReuse]和[super setSelected:selected],因为您可能会阻止单元格的超类进行单元格选择

如果你需要进一步澄清这个问题,请打我。