UITableView滚动不流畅

Ale*_*akh 18 uitableview uiimage smooth-scrolling ios xamarin

我在UITableView上使用包含UIImageView的UITableViewCell进行平滑滚动问题.在StrackOverflow上可以找到类似的问题,但是所提出的解决方案都没有帮助我彻底摆脱滞后.

我的情况很常见:

  1. 图像存储在应用程序存储中(在我的应用程序包示例中)
  2. 图像可能有不同的大小(500x500,1000x1000,1500x1500)
  3. 我需要在UITableView中显示那些图像,其中UIImageView大小为120x120(视网膜)

我遵循了多个优化技巧,并设法优化滚动.不幸的是它仍然不完美.这是我的情景:

  1. 首先,我将所有图像加载/处理/调整大小逻辑移动到后台线程
  2. 启用UITableViewCell重用
  3. 一旦UITableViewCell在视图中我清除旧值(设置为null)并启动后台线程来加载图像
  4. 在这一点上,我们在后台线程,我添加500毫秒延迟,以避免经常设置新图像(如果我们正在快速滚动)(见下面的解释)
  5. 如果UIImage存在于静态图像缓存(带有UIImage实例的常规字典)中 - 获取那个并转到步骤9.
  6. 如果不是 - 使用url到app捆绑包(imageWithName)加载新图像(在现实世界中,场景图像将存储到应用程序存储,而不是捆绑)
  7. 加载图像后,使用图形上下文将其调整为120x120
  8. 将已调整大小的图像保存到静态图像缓存中
  9. 在这一点上我们有UIImage的实例和进程在后台线程.从这里开始,我们将使用给定的图像返回UI Thread
  10. 如果数据上下文被清除(例如UITableViewCell消失或被重用以显示另一个图像),我们将跳过当前可用图像的处理.
  11. 如果数据上下文相同 - 使用alpha动画(UIView.Animate)将UIImage分配给UIImageView
  12. 一旦UITableViewCell不在视图范围内 - 清除数据上下文

最初在开始新的后台线程之前获取图像(步骤1)是没有后台线程的UIImage缓存检查.在这种情况下,如果我们在缓存中有图像,我们会立即分配它,这会在快速滚动期间引入很大的延迟(只要我们立即获取图像,我们就会经常分配图像).我在下面的例子中评论了这些行.

还有两个问题:

  1. 在滚动期间的某个时刻,我仍然有一个小的滞后(当我将新的UIImage分配给UIImageView时.
  2. (这个更明显)当你点击项目并从细节返回时,在后退导航动画完成之前有一个延迟.

任何建议如何处理这两个问题或如何优化我的方案表示赞赏

请考虑使用Xamarin编写的示例,但我不相信Xamarin是导致问题的原因,只要我对ObjectiveC中编写的应用程序也有同样的问题.

平滑滚动测试应用程序

lon*_*ngi 10

你们每个人都试图TableView只用一张保存在你身上的120x120图片Bundle吗?这样你可以检查你的问题是否发生Image rendering

我建议您创建并使用所有图像的缩略图,而不是将所有图像的大小调整为120x120并将其保存在缓存中.你已经在某种程度上这样做了,但是你这样做了几次(每次你滚动或者你的缓存已经满了).

在我们的上一个项目中,我们有UICollectionView书籍封面.大多数封面都在400-800kb之间,滚动时的感觉非常糟糕.所以我们为每个图像创建了一个缩略图(缩略图大约40-50kb),并使用缩略图而不是真正的封面.奇迹般有效!我附上了缩略图创建功能

- (BOOL) createThumbnailForImageAtFilePath:(NSString *)sourcePath withName:(NSString *)name {

    UIImage* sourceImage = [UIImage imageWithContentsOfFile:sourcePath];
    if (!sourceImage) {
        //...
        return NO;
    }

    CGSize thumbnailSize = CGSizeMake(128,198);

    float imgAspectRatio = sourceImage.size.height / sourceImage.size.width;
    float thumbnailAspectRatio = thumbnailSize.height/thumbnailSize.width;

    CGSize scaledSize = thumbnailSize;

    if(imgAspectRatio >= thumbnailAspectRatio){
         //image is higher than thumbnail
         scaledSize.width = scaledSize.height * thumbnailSize.width / thumbnailSize.height;
    }
    else{
        //image is broader than thumbnail
        scaledSize.height = scaledSize.width * imgAspectRatio;
    }

    UIGraphicsBeginImageContextWithOptions( scaledSize, NO, 0.0 );
    CGRect scaledImageRect = CGRectMake( 0.0, 0.0, scaledSize.width, scaledSize.height );
    [sourceImage drawInRect:scaledImageRect];
    UIImage* destImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    NSString* thumbnailFilePath = [[self SOMEDIRECTORY] stringByAppendingPathComponent:name];

   BOOL success = [UIImageJPEGRepresentation(destImage, 0.9) writeToFile:thumbnailFilePath atomically:NO];

return success;
Run Code Online (Sandbox Code Playgroud)

}