【问题标题】:How can I customize the selection state of my UICollectionViewCell subclass?如何自定义 UICollectionViewCell 子类的选择状态?
【发布时间】:2012-12-01 08:50:33
【问题描述】:

我有一个自定义 UICollectionViewCell 子类,它覆盖 initWithFrame:layoutSubviews 以设置其视图。但是,我现在正在尝试做两件我遇到麻烦的事情。

1) 我正在尝试在选择时自定义 UICollectionViewCell 的状态。例如,我想将UIImageView 中的一张图片更改为UICollectionViewCell

2) 我想在UICollectionViewCell 中为UIImage 设置动画(光反弹)。

谁能指出我正确的方向?

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    MyCollectionViewCell *cell = (MyCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
    [cell setSelected:YES];
}

【问题讨论】:

    标签: iphone objective-c ios uicollectionview uicollectionviewcell


    【解决方案1】:

    在您的自定义UICollectionViewCell 子类中,您可以在isSelected 属性上实现didSet

    斯威夫特 3:

    override var isSelected: Bool {
        didSet {
            if isSelected {
                // animate selection
            } else {
                // animate deselection
            }
        }
    }
    

    斯威夫特 2:

    override var selected: Bool {
        didSet {
            if self.selected {
                // animate selection
            } else {
                // animate deselection
            }
        }
    }
    

    【讨论】:

    • 你如何区分这两种状态?当我点击单元格时,我一直在执行if 块。
    • @Isuru 如果您一遍又一遍地点击同一个单元格,它将每次都将其设置为 true。尝试点击另一个单元格。
    • 这不是推荐的方法。它可以(并且确实)引起很多问题,尤其是在您处理单元格组的选择和突出显示时。正如 Apple 的文档所说,最好响应 UICollectionView 子类中的选择和突出显示,而不是单元格。这样,您的 UICollectionViewCell 负责维护和指导状态;不是细胞。因此,您应该响应 'collectionView(_ collectionView:, didSelectItemAt indexPath:)',获取单元格(或 collectionView.visibleCells)并在那里设置状态和动画。干杯。
    • 这是不稳定的。在某些情况下不会调用 isSelected “didSet”。 (尝试滚动一个集合视图并快速选择单元格,在某些时候它不会被调用)
    【解决方案2】:

    在您的自定义 UICollectionViewCell 子类中,您可以像这样覆盖 setSelected:

    - (void)setSelected:(BOOL)selected {
        [super setSelected:selected];
    
        if (selected) {
            [self animateSelection];
        } else {
            [self animateDeselection];
        }
    }
    

    我发现在重复触摸时会在单元格上调用此方法,即使它已被选中,所以您可能只想在触发不需要的动画之前检查您是否真的在更改状态。

    【讨论】:

    • 我更喜欢这个而不是接受的答案,因为这个函数已经内置了,所以如果你不想的话,你甚至不必覆盖 didSelectItemAtIndexPath。
    • 那是正确的,但你可能不想在setSelected 中滚动你自己的动画块,因为有时不应该对选定状态的转换进行动画处理(例如,当用于选定的项目被重用于未选定的项目)。对于 (de)selectItemAtIndexPath:animated:animated == YES 的调用,最好依靠集合视图本身提供的动画。
    • 这是一种错误的方法,因为在重新加载时你会得到错误的动画。
    • 我喜欢这个,因为行为属于我的单元类,而不是控制器类。我正在重用相同的单元格类,并且单元格的行为应该相同,无论它显示在哪个视图中,即使每个视图都有不同的数据源/委托/控制器。使用公认的答案,我需要在多个地方实现相同的东西,或者以某种方式让所有控制器都继承自一个定义行为的抽象控制器。
    • 问题中有两个不同的东西:状态和动画。状态可以通过这篇文章来修复。由于 collectionView 重新加载,动画无法播放。
    【解决方案3】:

    将公共方法performSelectionAnimations 添加到MyCollectionViewCell 的定义中,以更改所需的UIImageView 并执行所需的动画。然后从collectionView:didSelectItemAtIndexPath: 调用它。

    所以在 MyCollectionViewCell.m 中:

    - (void)performSelectionAnimations {
        // Swap the UIImageView
        ...
    
        // Light bounce animation
        ...
    }
    

    在你的UICollectionViewController:

    - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
        MyCollectionViewCell *cell = (MyCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
        [cell performSelectionAnimations];
    }
    

    请注意,我已经拨打了[cell setSelected:YES] 的电话,因为 UICollectionView 应该已经处理了这件事。来自文档:

    选择单元格并突出显示它的首选方法是使用集合视图对象的选择方法。

    【讨论】:

    • 我所有的UIImage 交换内容都是在从layoutSubviews 调用的方法中完成的。我应该直接从performSelectionAnimations 拨打layoutSubviews 吗?
    • 文档说不要直接调用layoutSubviews,而是使用setNeedsLayoutlayoutIfNeeded。无论如何,layoutSubviews 听起来像是交换+动画任务的错误位置。 layoutSubviews 的目的是在必要时定位子视图,包括第一次显示单元格时。但是您不是(重新)定位事物,我假设您只希望在选择单元格时执行这些任务。
    • 这个解决方案是完全错误的。至少因为单元格对象被重复使用,并且您最终会在滚动时显示错误的单元格。
    • 如果你调用collectionView?.selectItemAtIndexPath这也不起作用
    • 不,这是正确的方法。您可以获取有问题的单元格,根据需要测试可选性,然后告诉它执行动画或以其他方式更改其状态。您还可以查询 collectionView 的“visibleCells”属性,然后更改它们的状态/动画。这也允许 UICollectionView 一次控制单元组的状态。
    【解决方案4】:

    如果您想在选择时显示动画,那么以下方法可能对您有所帮助:

     - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
         NSLog(@"cell #%d was selected", indexPath.row);
    
    
         // animate the cell user tapped on
         UICollectionViewCell  *cell = [collectionView cellForItemAtIndexPath:indexPath];
    
         [UIView animateWithDuration:0.8
                               delay:0
                             options:(UIViewAnimationOptionAllowUserInteraction)
                          animations:^{
                              [cell setBackgroundColor:UIColorFromRGB(0x05668d)];
                          }
                          completion:^(BOOL finished){
                              [cell setBackgroundColor:[UIColor clearColor]];
                          }
          ];
    
    
     }
    

    【讨论】:

      【解决方案5】:

      以这种方式覆盖时不应与状态混淆:

      override var isSelected: Bool {
      
          get {
              return super.isSelected
          }
      
          set {
              super.isSelected = newValue
              .
              .
              .
          }
      }
      

      【讨论】:

        【解决方案6】:

        从 iOS 14 开始,您可以覆盖 updateConfiguration(using:) 并根据 UICellConfigurationState.isSelected 更新单元格

        【讨论】:

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