51

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

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

cellForItemAtIndexPath

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

我发现如果您将“selected 设置为 true” - 如果主对象和图像之间存在关系cellForItemAtIndexPath,则取消选择不再是一个选项。

didDeselectItemAtIndexPath

didSelectItemAtIndexPath

我用日志测试它们是否被调用。如果一个单元格设置为选中 - 下界会被调用,但如果我从未将一个单元格设置为选中,cellForItemAtIndexPath我可以选择和取消选择所有我想要的。

这是集合视图应该工作的预期方式吗?我阅读了文档,但似乎并没有谈到这一点。我将文档解释为它以表格视图单元格的方式工作。有一些明显的变化

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

4

15 回答 15

91

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

现在的解决方案:我同时 [UICollectionViewCell setSelected:]调用和[UICollectionView selectItemAtIndexPath:animated:scrollPosition:]in [UICollectionView collectionView:cellForItemAtIndexPath:]

于 2013-07-23T13:48:19.767 回答
48

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

我不得不补充:

myCollectionView.allowsMultipleSelection = YES;
于 2013-12-15T11:25:47.440 回答
46

setSelected您的 Cell 类中有自定义方法吗?你[super setSelected:selected]用那个方法打电话吗?

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

于 2013-11-03T04:32:41.317 回答
44

这有点老了,但是因为我使用 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

它工作得很好!

于 2015-07-13T15:19:45.713 回答
10

我不知道为什么UICollectionView会如此凌乱,相比之下UITableViewController……我发现了一些事情。

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

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

collectionView:didSelectItemAtIndexPath:实际上是在collectionView选择单元格之后调用的。因此,名称“确实选择了”。

所以这就是你的情况(和我的情况,我不得不为此挣扎几个小时)。

用户再次触摸选定的单元格以取消选择。shouldSelectItemAtIndexPath:被调用来检查是否应该选择单元格。collectionView选择单元格然后被didSelectItemAtIndexPath调用。此时您所做的任何事情都是在单元格的selected属性设置为之后YES。这就是为什么类似的东西cell.selected = !cell.selected不起作用的原因。

TL;DR -通过调用和 returncollectionView取消选择委托方法中的单元格。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;
    }
}
于 2015-04-29T05:40:23.947 回答
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()
        }
    }

}
于 2015-12-08T18:45:49.477 回答
6

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

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

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

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

所以,答案是不要尝试在 cellForItemAtIndexPath 方法中选择单元格选择您希望最初选择的单元格的最佳位置是在 UICollectionViewController 的 viewWillAppear 方法中。在该方法中,通过调用 UICollectionView.selectItem(at:animated:scrollPosition:) 选择所有需要的单元格,并且不要直接在您的单元格上设置 isSelected。

于 2019-06-07T22:41:24.617 回答
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
    }

}

我找到的简单解决方案

于 2016-02-09T17:12:37.800 回答
2

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

于 2017-02-14T21:23:52.600 回答
2

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

  1. 检查您是否已collectionView.allowsSelection设置为YES
  2. 检查您是否已collectionView.allowsMultipleSelection设置为YES(如果您需要该功能)

现在是风扇部分。如果您听 Apple 并设置backgroundColorcell.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

cell.selected因此,如果您想使用 selectedBackgroundView (使用and打开/关闭selectItemAtIndexPath...),请执行以下操作:

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

它应该工作得很好。

于 2016-03-25T11:25:28.930 回答
1

你看过:

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

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

我认为您的问题可能源于混淆,如果您cell.selected = YES以编程方式设置,didSelectItemAtIndexPath:则没有被调用的原因是因为仅在 collectionView 本身负责单元格的选择时使用(例如,通过点击)。

于 2013-04-05T22:10:23.643 回答
1

我不知道我是否理解这个问题,但选定的状态是按单元格设置的,并将包括单元格内的所有子视图。您没有解释“一个主要对象有许多与之相关联的图像”是什么意思。在子视图中关联?或者你到底是什么意思?

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

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

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

于 2013-03-11T06:44:18.907 回答
1

当同时调用和调用 不起作用时,请尝试在块内调用它们 。[UICollectionViewCell setSelected:][UICollectionView selectItemAtIndexPath:animated:scrollPosition:][UICollectionView collectionView:cellForItemAtIndexPath:]dispatch_async(dispatch_get_main_queue(), ^{});

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

于 2016-11-29T15:25:32.337 回答
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
            }
        }
    }
于 2020-10-14T10:05:59.873 回答
-1

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

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

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

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

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

如果您需要进一步澄清这个问题,请联系我。

于 2015-11-04T02:45:16.960 回答