UITableView滚动不流畅 [英] UITableView scrolling is not smooth

查看:138
本文介绍了UITableView滚动不流畅的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的UITableView上有包含UIImageView的UITableViewCell,因此出现了平滑滚动的问题.在StrackOverflow上都可以找到类似的问题,但是所提出的解决方案都无法帮助我完全摆脱这一滞后.

I have the smooth scrolling issue at my UITableView with UITableViewCell which contains UIImageView. Similar issues could be found all over the StrackOverflow but none of the proposed solutions helped me to completely get rid of the lag.

我的情况很普遍:

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

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

I have followed multiple optimization tips and managed to optimize scrolling a lot. Unfortunately it is still not perfect. This is my scenario:

  1. 首先,我将所有图像加载/处理/调整大小逻辑移至后台线程
  2. 启用了UITableViewCell重用
  3. 在视图中出现UITableViewCell之后,我清除了旧值(设置为null)并启动后台线程来加载图像
  4. 这时我们处于后台线程中,我增加了500 ms的延迟,以避免经常设置新图像(以防我们快速滚动)(请参见以下说明)
  5. 如果UIImage存在于静态图像缓存(带有UIImage实例的常规词典)中,请获取该图像并转到步骤9.
  6. 如果不是-使用URL将捆绑包(imageWithName)中的新图像加载到应用捆绑包中(在现实情况下,图像将存储到应用程序存储中,而不是捆绑包中)
  7. 加载图像后,使用图形上下文将其尺寸调整为120x120
  8. 将调整大小后的图像保存到静态图像缓存中
  9. 在这一点上,我们有UIImage的实例,并且进程在后台线程中.从这里,我们返回给定图像的UI线程
  10. 如果清除了数据上下文(例如,UITableViewCell消失或被重新用于显示另一幅图像),我们将跳过对当前可用图像的处理.
  11. 如果数据上下文相同,请使用alpha动画(UIView.Animate)将UIImage分配给UIImageView
  12. 一旦UITableViewCell不可见-清除数据上下文
  1. first I moved all the image loading/processing/resizing logic to the background thread
  2. UITableViewCell reuse is enabled
  3. once UITableViewCell is in view I clear old values (settings to null) and start background thread to load the image
  4. at this point we are in background thread and I'm adding 500 ms delay to avoid settings new image to often (in case we are scrolling fast) (see below explanation)
  5. if UIImage exists at static image cache (regular dictionary with UIImage instances) - fetch that one and go to the step 9.
  6. if not - load new image from bundle (imageWithName) using url to app bundle (in real world scenario images will be stored to application storage, not bundle)
  7. once image is loaded resize it to 120x120 using graphics context
  8. save resized image to the static image cache
  9. at this point we have instance to UIImage and process is in the background thread. From here we move back to UI Thread with the given image
  10. if data context was cleared (for example UITableViewCell disappeared or was reused to display another image) we skip processing of the currently available image.
  11. if data context is the same - assign UIImage to UIImageView with an alpha animation (UIView.Animate)
  12. once UITableViewCell is out of view - clear the data context

最初,在没有背景线程的情况下,在开始新的背景线程以在此处获取图像之前(步骤1)是UIImage缓存检查.在这种情况下,如果我们将图像保存在缓存中,则会立即对其进行分配,这在快速滚动期间会带来很大的延迟(我们将图像分配给通常只要我们立即获取它们就可以).这些行在下面附上的示例中有注释.

Originally before starting new background thread to fetch the image here (step 1) was UIImage cache check without background thread. In this case if we have the image in the cache we assign it instantly and this introduces a great lag during fast scrolling (we assign images to often as long as we fetch them instantly). Those lines are commented at my example attached below.

仍然存在两个问题:

  1. 在滚动过程中的某个时刻,我仍然有一个小的滞后(在 将新的UIImage分配给UIImageView的时刻.
  2. (这一点更引人注目),当您点按项目并返回详细信息时,在完成向后导航动画之前会出现滞后.
  1. at some point during scrolling I still have a small lag (at the moment when I'm assign new UIImage to UIImageView.
  2. (this one is more noticeable) when you tap on item and go back from details there is a lag right before back navigation animation is finished.

任何人都建议如何处理这两个问题或如何优化我的情况

请考虑使用Xamarin编写的示例,但只要我也对用ObjectiveC编写的应用程序存在相同的问题,我不认为Xamarin是问题的原因.

Please take into account that sample written in Xamarin but I don't believe that Xamarin is the cause of the problem as long as I have the same issue for the app written in ObjectiveC as well.

平滑滚动测试应用程序

推荐答案

您是否都尝试过只用保存在Bundle中的一张120x120图像填充TableView?这样,您就可以检查Image rendering

Did you every tried to populate your TableView with only one 120x120 Image which is saved in your Bundle? This way you can check, if the problem occurs of your Image rendering

我建议您创建并使用所有图像的缩略图,而不是将所有图像的大小调整为120x120并将其保存在缓存中.您已经以某种方式进行了此操作,但是您已经进行了几次(每次滚动或缓存已满时).

Instead of resizing all your images to 120x120 and save them in cache, I would recommend creating and using a thumbnail of all your images. You are somehow already doing this, but you are doing this couple of times (everytime you are scrolling or if your cache is full).

在我们的上一个项目中,我们有一个UICollectionView带有书的封面.大多数封面的大小在400-800kb之间,滚动时的感觉真的很差.因此,我们为每个图像创建了一个缩略图(缩略图约40-50kb),并使用了缩略图代替了真实的封面.奇迹般有效!我附加了缩略图创建功能

In our last project we had a UICollectionView with book covers. Most of the covers were between 400-800kb big and the feeling while scrolling was really bad. So we created a thumbnail for each image (thumbails about 40-50kb) and used the thumbnails instead of real covers. Works like a charm! I attached the thumbnail creation function

- (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;

}

这篇关于UITableView滚动不流畅的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆