【问题标题】:UICollectionView reorder cells after scrollingUICollectionView 滚动后重新排序单元格
【发布时间】:2014-09-05 07:14:21
【问题描述】:

我已经在我的实现中添加了这个 UICollectionViewDelegate:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    SAPCollectionViewCell *collectionViewCell = (SAPCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"SAPCollectionViewCell" forIndexPath:indexPath];

    NSInteger index = indexPath.item + indexPath.section * 2;

    NSString *imagePath = [_images objectAtIndex:index];

    collectionViewCell.index = index;

    [collectionViewCell setImageWithPath:imagePath];

    collectionViewCell.delegateCell = self;

    return collectionViewCell;
}

在我的自定义单元格中,我有这个方法:

- (void)setImageWithPath:(NSString *)imagePath
{
    if (!self.imageView)
    {
        CGRect rect = self.contentView.frame;

        self.imageView = [[UIImageView alloc] initWithFrame:rect];

        [self.contentView addSubview:self.imageView];

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

            UIImage *image = [UIImage imageFromPath:imagePath];

            UIImage *resizedImage = [UIImage imageWithImage:image scaledToWidth:rect.size.width];

            dispatch_async(dispatch_get_main_queue(), ^{

                [self.imageView setImage:resizedImage];

            });
        });
    }
}

所以你可以看到如果单元格没有 UIImageView 然后我开始创建它,在后台我从本地路径获取图像并将其调整为单元格内容视图宽度,然后在主队列中我将图像设置为 UIImageView。

这部分工作得很好,但是当我尝试滚动我的 UICollectionView 时,例如有 10 张图片我注意到,例如,如果前 2 张顶部图片在我向下滚动时消失了,然后当我滚动回顶部时,图片的位置会发生变化。

这是向下滚动之前的图像状态:

我滚动UIColectionView回到顶部后的这个状态:

所以你可以首先看到项目改变了他们的位置。正如我在上面的代码中设置的if (!self.imageView),它应该意味着图像永远不会被创建两次或更多次。

我打开了调试器,正在检查这个方法:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

因此,当 UICollectionView 第一次创建单元格时,图像路径会一一返回。

第一次 UICollectionViewCell 有 0x8fbc1d0 第二个有 0x8d0a4c0 地址

但是当我向下滚动然后向上滚动时,调试器首先显示了第二个地址 0x8d0a4c0,然后显示了 0x8fbc1d0

但我不明白为什么物品会改变顺序。或者这里可能是另一个问题?

此外,我在代码中没有任何方法可以为我重新排序单元格。只有少数 UICollection 视图方法委托配置单元格的数量并创建它们。

此外,如果我删除 if (!self.imageView) 似乎一切正常,但我的代码每次调用调度都对我没有好处,因为当我将图像调整为单元格大小时,我不需要执行两次。

【问题讨论】:

    标签: ios uicollectionview uicollectionviewcell reuseidentifier


    【解决方案1】:

    当您将这两个项目滚动到屏幕外时,您的 CollectionView 会将关联的单元格放回“队列”。当您再次向上滚动时,cellForItemAtIndexPath 中的 dequeueResuableCellwithReuseIdentifier 从该队列中检索它们,但(如您所见)不一定以相同的顺序。因此,项目 0 的单元格已用于项目 1,反之亦然。如您所见,if (!self.imageView) 实际上会阻止加载正确的图像。如果您想避免每次都检索和调整它们的大小,那么我会将(调整大小的)imageViews 存储在一个数组中。

    【讨论】:

      【解决方案2】:
      - (void)setImageWithPath:(NSString *)imagePath
      {
          if (!self.imageView)
          {
              CGRect rect = self.contentView.frame;
      
              self.imageView = [[UIImageView alloc] initWithFrame:rect];
      
              [self.contentView addSubview:self.imageView];
      
          }
      
          if (![self.imagePath isEqualsToString:imagePath] && self.imageView.image == nil)
              {
                  self.imagePath = imagePath;
      
                  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      
                      UIImage *image = [UIImage imageFromPath:imagePath];
      
                      UIImage *resizedImage = [UIImage imageWithImage:image scaledToWidth:rect.size.width];
      
                      dispatch_async(dispatch_get_main_queue(), ^{
                          if ([self.imagePath isEqualsToString:imagePath])
                          {
                              [self.imageView setImage:resizedImage];
                          }
      
                      });
      
                  });
              }
      }
      

      【讨论】: