UIActivityIndi​​catorView 没有在 UICollectionViewCell 中旋转

Posted

技术标签:

【中文标题】UIActivityIndi​​catorView 没有在 UICollectionViewCell 中旋转【英文标题】:UIActivityIndicatorView not spinning in UICollectionViewCell 【发布时间】:2014-03-18 08:30:53 【问题描述】:

我的收藏视图底部加载了一个自定义单元格。它唯一的工作是显示一个活动指示器视图——这发生在应用程序进行新的工作调用时。

所以我像这样将它添加到单元格中:

BBLoaderCell *loaderCell = [collectionView dequeueReusableCellWithReuseIdentifier:@"LoaderCell" forIndexPath:indexPath];


UIActivityIndicatorView * activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityIndicator.hidesWhenStopped = YES;
activityIndicator.hidden = NO;
activityIndicator.center = loaderCell.imageView.center;
activityIndicator.tag = 10;

[loaderCell.imageView addSubview:activityIndicator];

    [activityIndicator startAnimating];
    return loaderCell;

这在我视图的最后一个单元格中显示了一个活动指示器 - 但是它没有旋转。有什么想法吗?

找到解决方案

根据 cmets - 这是一个线程问题。我还接受了将代码移动到单元格的自定义 nib 文件的建议。

这里是重构的代码:

BBLoaderCell *loaderCell = [collectionView dequeueReusableCellWithReuseIdentifier:@"LoaderCell" forIndexPath:indexPath];
    loaderCell.backgroundColor = [UIColor clearColor];

     if (self.loadingMore == NO)
        dispatch_async(dispatch_get_main_queue(), ^
            activityIndicator.hidden = YES;
            [loaderCell.spinner stopAnimating];
        );
    
     else if (self.loadingMore == YES)
    dispatch_async(dispatch_get_main_queue(), ^
        activityIndicator.hidden = NO;
        [loaderCell.spinner startAnimating];
    );
    

    return loaderCell;

这是我需要的工作。

谢谢各位!

【问题讨论】:

我认为这可能与线程有关,您可以尝试以下操作吗:[activityIndicator performSelector:@selector(startAnimating:) withObject:nil afterDelay:1];,动画应该在单元格加载后一秒钟开始。 只是一个小建议,如果您在自定义单元格中使用 nib 文件,只需在实际的 .xib 中添加活动指示器,而不是在 cellForRow 中添加它,这样可以使代码更简洁 谢谢各位。你的两个cmets都有帮助。我会投票两个。 @hless 请让您的评论成为答案,以便我标记它。 很高兴它有所帮助,尽管我对答案不是 100% 满意。希望我确切地知道是什么原因造成的...... 我认为这与在后台线程上执行 UI 更新有关。根据 Apple 的说法,哪一个不应该发生并导致上述问题? 【参考方案1】:

我认为这可能与线程有关(例如,主线程上的 UI 尚未准备好为指示器设置动画)。您可以尝试以下方法:

[activityIndicator performSelector:@selector(startAnimating:) withObject:nil afterDelay:1];

不过,这只是一个可能的建议,您应该尝试不同的变体,并检查哪个变体正确且及时地将动画强制到主线程上。另一种变化:

dispatch_async(dispatch_get_main_queue(), ^
    [activityIndicator startAnimating];
);

【讨论】:

【参考方案2】:

您很可能会在很短的时间内多次致电reloadData。也许已经在下一帧。默认情况下,活动指示器在停止时隐藏。这就是发生的事情:

    首先 reloadData 它显示微调器 第二个 reloadData 也会重新加载单元格,并且微调器会自行隐藏 现在微调器被隐藏了 您滚动滚动,但单元格被重复使用。微调器仍然隐藏

您可以设置activityIndicator.hidesWhenStopped = false。微调器现在应该始终可见。但它没有旋转。

添加这个将恢复旋转。

override func prepareForReuse() 
   activityIndicator.startAnimating()

另一个问题可能是颜色。也许微调器的颜色与背景相同。尝试像这样设置微调器的颜色:

activityIndicator.color = .red

您可以使用“Debug View Hierarchy”按钮检查微调器是否存在

它将显示当前可见屏幕的线框

【讨论】:

【参考方案3】:

更简洁的解决方案是在 willDisplay 委托方法中启动动画:

public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) 
  (cell as? BBLoaderCell)?.activityIndicatorView.startAnimating()

由于在 ios 10 或更高版本上,默认启用预取,即使单元格多次滚动进出屏幕,也可能只有 1 个 cellForItemAt 调用。当单元格滚动出屏幕时,似乎调用了stopAnimating()isAnimating 也变为false)。因此,在单元格第二次进入屏幕后,在cellForItemAt 中使用异步延迟可能会失败。在 iOS 11 上仍然如此

由于每当单元格进入屏幕时都会调用willDisplay,因此我们可以可靠地在那里重新启动动画

【讨论】:

【参考方案4】:

在我的情况下,我在 customCell 上为 tableView 使用了 activityIndi​​cator,但我遇到了同样的问题,即使在写下 activityIndi​​cator.startAnimating() 之后加载也没有移动。

经过几个小时的尝试,我想出了一个解决方案。

override func prepareForReuse() 
       activityIndicator.startAnimating()

只需使用方法 prepareForReuse() 显示当您重用 activityIndi​​cator 正在制作动画的 customCell 时

【讨论】:

以上是关于UIActivityIndi​​catorView 没有在 UICollectionViewCell 中旋转的主要内容,如果未能解决你的问题,请参考以下文章

UIActivityIndi catorView未在webview中显示

UIButton里面的UIActivityIndi​​catorView

Swift UIPageViewController & UIActivityIndi​​catorView

如何在 UIAlertView 的中心添加 UIActivityIndi​​catorView?

为啥是UIActivityIndi​​catorView!展开时为零?

如何在 UICollectionViewCell 中将 UIActivityIndi​​catorView 居中?