UICollectionView选择和取消选择问题

问题描述:

所以我有一个主要的对象,有许多图像与它关联。图像也是一个对象。UICollectionView选择和取消选择问题

说你有一个集合视图控制器,并在控制器,你有

cellForItemAtIndexPath

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

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

didDeselectItemAtIndexPath 

didSelectItemAtIndexPath 

我有一个记录测试,看看他们是否被调用。如果一个单元格被设置为选中 - 下一个被调用,但如果我从来没有设置一个单元格在cellForItemAtIndexPath中被选中,我可以选择和取消选择所有我想要的。

这是集合视图应该工作的预期方式吗?我阅读了文档,似乎没有谈论这是如此。我将文档解释为表示它以表格视图单元格的方式工作。有几个明显的变化

这也显示了控制器设置正确,并使用相应的委托方法.... hmmmm

我不知道我理解的问题,但选择的状态设置每个单元格并包含单元格内的所有子视图。你不能解释你的意思是“主对象有许多与之相关的图像”。在子视图中关联?或者你的意思是什么样的联系?

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

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

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

+1

有没有人使用过集合视图,在cellForItemAtIndexPath中将选择设置为YES并且能够取消选择该单元格?我已经建立了两个测试项目,两者的工作原理都是一样的。只要在ce​​llForItemAtIndexPath中将selected设置为true,就不会再次调用取消选择。 – bworby 2013-03-12 04:46:44

+0

不,我认为你不能这样做。如果我在cellLForItemAtIndexPath中设置了一个单元格,则该项目的行为与集合视图(即所选背景)的初始显示中所选择的相同。然而,如果我查看[collectionView indexPathsForSelectedItems]的值,我会得到零 - 这表明我不会有通过常规手段取消选择它的方式。 您可能可以设置cell.selected == NO的值,因为我没有尝试过。但是,如果你无法获得所选项目的索引路径,那肯定会使集合视图更难以使用。 – RegularExpression 2013-03-12 05:03:26

+0

这看起来不奇怪吗?我可能会考虑错误,但我可以肯定地看到,允许某些单元格按照选定的方式启动并能够被取消选择的用途很多。 – bworby 2013-03-13 21:55:53

你有没有看:

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

请详细写明您的问题,也许我们可以得到它的底部。我刚刚花了一些时间与UICollectionView。

我认为你的问题可以从混乱被制止,如果你设置cell.selected = YES编程,原因didSelectItemAtIndexPath:是没有得到所谓的是因为这是只使用时的CollectionView本身负责细胞的选择(例如,通过自来水)。

我有同样的问题,即。在[UICollectionView collectionView:cellForItemAtIndexPath:]中设置cell.selected = YES然后不能通过点击选择单元格。

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

+2

奇怪的,它应该是必要的 - 但它的工作原理..它不会导致无限循环与didSelectItemAtIntexPath委托.. – 2013-07-30 09:58:36

+5

有没有人发现,因为这更好的解决办法,提出了?这个解决方案也适用于我,但这可能是一个错误。 – itslittlejohn 2014-02-20 20:32:33

+1

您是SAINT!我告诉你!不确定在ScrollPosition枚举的具体情况,但它的工作。 (Y) – MrOli3000 2014-09-05 11:00:45

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

我有一个神秘的问题,我正在使用多个选择,一旦他们被选中,我无法取消选择单元格。调用超级方法解决了这个问题。

+6

我无法相信,经过5年的艰难的iOS编程,我错过了如此明显的东西。咄! – Linasses 2013-11-19 12:56:42

+0

这是我的问题! – NickDK 2015-02-20 16:31:32

+0

这可以很容易错过 – 2cupsOfTech 2016-02-25 17:29:55

我有一个取消选择问题UICollectionView,我发现我不允许在collectionView上进行多重选择。所以当我测试的时候,我总是在同一个单元格上尝试,如果单选是ON,你不能取消已经选择的单元格。

我不得不添加:

myCollectionView.allowsMultipleSelection = YES; 
+0

这是正确的答案 – naz 2014-09-30 10:27:04

+0

我想大多数人错过的原因,是因为它没有暴露在IB收集意见,对不对?我已经找到它了,在IB的任何地方都找不到它。 – 2016-12-21 12:12:37

我不知道为什么UICollectionView是如此凌乱这样比较UITableViewController ... 有几件事情我发现。

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

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

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

所以这就是你的情况发生了什么(和我的情况,我不得不在这方面搏斗几个小时)。

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

TL; DR - 请collectionView通过调用deselectItemAtIndexPath:animated:取消选择委托方法collectionView:shouldSelectItemAtIndexPath:中的单元格,并返回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; 
    } 
} 
+0

独特而正确的答案。没有设置collectionView.allowsMultipleSelection = YES; – WINSergey 2016-10-21 08:31:37

这是慈祥的老人,但由于我使用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 

它完美!

+0

这解决了我的问题。非常感谢。 – Ismail 2015-11-16 12:04:21

+0

其他选项并不适合我,这一个完美工作。 – Stuart 2016-08-03 08:51:21

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

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

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

您不应该直接在您的collectionView数据源中直接插入单元格的背景颜色。另外,作为最后一点,如果你在单元的类中实现了这些,不要忘记调用[super prepareForReuse]和[super setSelected:selected],因为你可能会阻止单元的超类做单元选择。

如果您需要关于此主题的进一步说明,请打我。

这是我对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() 
     } 
    } 

} 
+0

这可以工作,但我需要更改所选单元格的边框颜色,这在单元类中不起作用。你能提出一些建议吗? – 2016-12-20 13:00:56

+0

@ArpitDhamane这不适用于我,我使用的是Swift 3 Xcode 8.1。我只能在“collectionView:UICollectionView,cellForItemAt indexPath”里面改变单元格样式:“ – user30646 2017-04-22 18:34:45

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 
    } 

} 

简单的解决方案,我发现

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

  1. 检查你是否有collectionView.allowsSelection设置为YES
  2. 检查你是否有collectionView.allowsMultipleSelection设置为YES(如果你需要的能力)

现在到了风扇部分。 如果您聆听Apple并将其设置为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]; 

,它应该只是罚款。

+1

”你从哪里得到'pviews'?我得到一个错误:在Xcode 7.2.1上无法识别的命令'pview'.',lldb-340.4.119.1 – 2016-04-25 18:15:03

+0

https://github.com/facebook/chisel – 2016-04-26 07:28:48

+2

'pviews cell'只是'po [cell recursiveDescription]'调用,你可以在任何视图上做lldb console – 2016-04-26 07:31:31

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

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

我使用的是自定义单元格子类,对于我来说,我只需要在子类中设置。