【问题标题】:UICollectionView - didDeselectItemAtIndexPath not called if cell is selectedUICollectionView - 如果选择了单元格,则不调用 didDeselectItemAtIndexPath
【发布时间】:2013-12-04 16:21:12
【问题描述】:

我要做的第一件事是设置选中的单元格。

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
    cell.selected = YES;
    return cell;
}

并且单元格被成功选中。 如果用户触摸选定的单元格,则应取消选择该单元格并调用代表。但这永远不会发生。

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"%s", __PRETTY_FUNCTION__);
}

- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"%s", __PRETTY_FUNCTION__);
}

我知道如果我以编程方式设置选择,则不会调用代表。 委托和数据源已设置。

但是,这个委托被调用:

- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"%s", __PRETTY_FUNCTION__);
    return YES;
}

如果我删除 cell.selected = YES,那么一切正常。有没有人可以解释这种行为?

【问题讨论】:

  • 当您使用 cellforItemAtIndexPath 时,它会为 tableview 中的每个单元格调用,所以基本上您正在尝试设置每个选定的单元格。你想达到什么目的?

标签: ios objective-c uicollectionview


【解决方案1】:

问题是,该单元格已被选中,但 UICollectionView 对此一无所知。额外拨打UICollectionView 即可解决问题:

[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone]; 

完整代码:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
    cell.selected = YES;
    [collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
    return cell;
}

我保留这个问题是为了帮助可能面临同样问题的人。

【讨论】:

  • 你好@zeiteisen。在我的情况下,当我选择一个单元格didSelectItemAtIndexPath 时被调用,但是当第二次单击单元格时它不会调用didDselectItemAtIndexPath。我想在这两种方法中更改单元格的内容。我该怎么做?
  • 它有效,但我还需要理解为什么需要它:集合视图回调说用户选择了单元格->我要求它重新加载单元格,以便我可以直观地反映更改,那么当它询问单元格时,我需要告诉它(再次)选择它吗?
【解决方案2】:

我认为@zeiteisen 提供的解决方案是一种解决方案。实际的事情在于选择模式。在属性cell.selected 中无需设置任何内容。

UICollectionView 名称 allowsMultipleSelectionallowsSelection 有两个属性。

allowsMultipleSelection 默认为NOallowsSelectionYES

如果你只想选择一个单元格,那么代码@初始化看起来像

yourCollectionView.allowsMultipleSelection = NO;
yourCollectionView.allowsSelection = YES; //this is set by default

然后设置将允许您一次只选择一个单元格,不少于不少。 您必须至少选择一个单元格。 除非您选择另一个单元格,否则不会调用 didDeselectItemAtIndexPath。点击已选择的UICollectionViewCell 不会使其取消选择。这是实施背后的政策。

如果你想选择多个单元格,那么代码@the初始化应该如下所示:

yourCollectionView.allowsMultipleSelection = YES;
yourCollectionView.allowsSelection = YES; //this is set by default

然后设置将允许选择多个单元格。此设置允许选择一个或多个UICollectionViewCell。选择的单元格数将是

0 <= number_selected_cell <= total_number_of_cell

这是多个单元格选择背后的策略。

如果您打算使用上述任何一种方法,欢迎您使用 apples api 而不会额外感到头疼,否则您必须找到一种方法来使用您自己的代码或 apple 的 api 潜入您的目标。

【讨论】:

  • 你是对的,简单地说:如果用户再次点击它,集合视图不会自动取消选择已选择的单元格。 allowMultipleSelection 属性文档中的说明是错误的。对我来说,苹果这样实现它是很奇怪的,为了实现“再次点击并取消选择”行为,我们应该自己维护一个选择标志。
  • 这应该被选为正确答案。关键是设置allowMultipleSelection=YES。
  • 我遇到了@Chris 提到的问题。显然这是因为在我的自定义 collectionView 单元格中覆盖了 setIsSelected 而没有调用 super.选择和取消选择按照文档中的说明进行。
【解决方案3】:

我有同样的问题。我在表格加载时预先选择了单元格,但我不得不双击一个单元格来取消选择它。 @zeiteisen 的回答帮助了我。但是,我正在使用 Swift 3,所以我想我会在 Swift 中给出答案。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell

    if /*Test for Selection*/ {
        cell.isSelected = true
        collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .left)
    }        
    return cell
}

【讨论】:

    【解决方案4】:

    将此行添加到您的 didSelectItemAtIndexPath 方法中

    [collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:nil]
    

    【讨论】:

      【解决方案5】:

      在我的例子中,我想改变按钮的背景,换句话说就是集合视图中单元格的背景:

      class CustomCVCell: UICollectionViewCell {
      
      override var isSelected: Bool {
              didSet {
                  grayBackgroundViewWithImage.image =
                      isSelected ? UIImage(named: "") : UIImage()
              }
          }
      

      在存储集合视图的主类中创建这个变量:

      class CustomViewController: UIViewController {
      
      ///save the indexPath of last selected cell
      private var lastSelectedIndexPath: IndexPath? }
      

      在 viewDidLoad() 中将此值设置为 false:

      customCollectionView.allowsMultipleSelection = false
      

      数据源中的更多代码。在我的情况下,应该选择第一个单元格:

      func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
          let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomCVCell.cellID(),
                                                        for: indexPath) as! CustomCVCell
          
          if indexPath.row == 0 {
              lastSelectedIndexPath = indexPath
              cell.isSelected = true
          }
          
          //update last select state from lastSelectedIndexPath
          cell.isSelected = (lastSelectedIndexPath == indexPath)
          
          return cell
      }
      

      委托中的更多代码:

      ///UICollectionViewDelegate
      func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
          guard lastSelectedIndexPath != indexPath else { return }
      
               if let index = lastSelectedIndexPath {
                  let cell = collectionView.cellForItem(at: index) as! CustomCVCell
                  cell.isSelected = false
                }
      
                let cell = collectionView.cellForItem(at: indexPath) as! CustomCVCell
                cell.isSelected = true
          lastSelectedIndexPath = indexPath
      }
      

      【讨论】:

        【解决方案6】:

        重新加载单元格对我来说是解决方案。我需要的是在单元格中更改图像片刻。我将图像分配给 cellForItemAtIndexPath 中的 imageView,当用户触摸单元格时,我会更改图像并运行 mycode,然后重新加载单元格。

         func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
                let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MenuCollectionViewCell
                cell.backgroundImageView.image = UIImage(named: "selected")
                // handle tap events
                collectionView.reloadItemsAtIndexPaths([indexPath])
            }
        

        希望对某人有所帮助。

        【讨论】:

          【解决方案7】:

          在我的情况下,它是由使用相同的逻辑引起的

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

          至于

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

          以及选择单元格时,突出的是返回错误 - 这阻止了我取消选择该细胞。

          希望这会节省一些人的时间 :)

          【讨论】:

            【解决方案8】:

            我遇到了同样的问题,如果您进一步调查,您会发现不仅没有调用 diddiselect,而且单元格也没有感知到触摸本身。为我解决的问题是允许异步执行选择并手动设置 selectItem 。 在 cellForItemAt 内。

                   DispatchQueue.main.async {
                        cell.isSelected = true
                        collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .init())
                    }
            

            如果您不想看到动作,请在动画上使用 .init() 和 false。如果您不使用 async 块包装它,您将看到 UI 在滚动时跳跃。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-12-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多