UITableView滚动不顺畅

我有我的UITableView UITableViewCell包含UIImageView的顺利滚动问题。 类似的问题可以在整个StrackOverflow中find,但没有一个提出的解决scheme帮助我完全摆脱了滞后。

我的情况很常见:

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

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

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

最初在开始新的后台线程来获取图像在这里(步骤1)是UIImagecaching检查没有后台线程。 在这种情况下,如果我们在caching中有图像,我们立即分配图像,并且在快速滚动期间引入了很大的滞后(我们只要立即获取图像就会分配图像)。 这些行在我下面的示例中进行了评论。

还有两个问题:

  1. 在滚动过程中的某一点,我仍然有一个小滞后(在我将新的UIImage分配给UIImageView的那一刻)。
  2. (这个更明显),当你点击项目并从细节返回时,在返回导航animation结束之前有一个滞后。

任何build议如何处理这两个问题,或如何优化我的情况,表示赞赏

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

平滑的滚动testing应用程序

你有没有试图填充你的TableView只有一个120×120图像保存在你的Bundle ? 这样您可以检查,如果您的Image rendering出现问题

我不build议将所有图像的大小调整为120×120并将其保存在caching中,而是build议您创build并使用所有图像的缩略图。 你不知何故已经这样做了,但是你正在做几次(每次你滚动或者如果你的caching已满)。

在我们的最后一个项目中,我们有一本书封面的UICollectionView 。 大部分的封面都在400-800kb之间,滚动的感觉真的很差。 所以我们为每个图像创build了一个缩略图(缩略图大约40-50kb),并使用缩略图而不是真正的封面。 奇迹般有效! 我附加了缩略图创buildfunction

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

}

尝试Facebook的asynchronous显示库。

https://github.com/facebook/AsyncDisplayKit

真的很容易使用..从他们的指导: http : //asyncdisplaykit.org/guide/

 _imageNode = [[ASImageNode alloc] init]; _imageNode.backgroundColor = [UIColor lightGrayColor]; _imageNode.image = [UIImage imageNamed:@"hello"]; _imageNode.frame = CGRectMake(10.0f, 10.0f, 40.0f, 40.0f); [self.view addSubview:_imageNode.view]; 

这在后台线程解码图像。

我不确定在Xamarin上使用iOS库是否容易,但是如果这很容易,请给出一个答案。

我分类Paul Hegarty的CoreDataTableViewController,并在CoreDataTableView中使用我的照片的缩略图。

请参阅第14讲标题为FlickrFetcher和Photomania的例子 。 您还需要在同一链接下载CoreDataTableViewController。

用适当的标题制作一个CoreData实体,并定义你想要的任何属性(数据variables)。 您需要定义两个“Transformable”属性,一个用于照片,一个用于缩略图。

然后在CoreDataTableView中加载你的缩略图:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

{NSArray * exceptions = [NSArray arrayWithObjects:@“SCR”,@“DNS”,@“NT”,@“ND”,@“NH”,nil];

 static NSString *CellIdentifier = @"resultsDisplayCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; } cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; MarksFromMeets *athleteMarks = [self.fetchedResultsController objectAtIndexPath:indexPath]; NSString* date = [ITrackHelperMethods dateToAbbreviatedString:athleteMarks.meetDate]; NSMutableString *title = [NSMutableString stringWithFormat:@"%@", athleteMarks.markInEvent]; NSMutableString *subTitle = [NSMutableString stringWithFormat:@"%@ - %@",date, athleteMarks.meetName]; [title replaceOccurrencesOfString:@"(null)" withString:@"" options:0 range:NSMakeRange(0, [title length])]; // cell.imageView.image = athleteMarks.photoThumbNail; // Don't like image in front of record. [cell.textLabel setFont:[UIFont fontWithName:@"Helvetica Neue" size:18]]; [cell.detailTextLabel setFont:[UIFont fontWithName:@"Helvetica Neue" size:16]]; [cell.detailTextLabel setTextColor:[UIColor grayColor]]; // make selected items orange if ([athleteMarks.eventPR integerValue] != 0 && (![exceptions containsObject:athleteMarks.markInEvent])) { title = [NSMutableString stringWithFormat:@"%@ (PR)",title]; [cell.textLabel setTextColor:[UIColor redColor]]; } else if ([athleteMarks.eventSB integerValue] != 0 && (![exceptions containsObject:athleteMarks.markInEvent])) { title = [NSMutableString stringWithFormat:@"%@ (SB)",title]; [cell.textLabel setTextColor:[UIColor orangeColor]]; } else { [cell.textLabel setTextColor:[UIColor grayColor]]; } cell.textLabel.text = title; cell.detailTextLabel.text = subTitle; cell.indentationLevel = indentationLevelOne; cell.indentationWidth = indentationForCell; return cell; 

}

如果你愿意,我可以给你一个实体的NSManagedObject子类的类别的例子。 此类别将照片和缩略图加载到CoreData实体中。 第一次会很慢。 但是,之后用户应该能够顺利滚动TableView,然后所有更新的结果将自动加载。 让我知道。

一件好事就是CoreData处理所有的内存pipe理。

祝你好运!

我没有足够的代表评论,所以这里有一个答案,这有助于我的tableview滚动性能:

  • 使tableview高度大于可视窗口。 单元格将加载“屏幕外”,并有助于提高滚动平滑度。
  • -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

这两个技巧让我的桌子真的很好。 我从API服务获取我的图像数据和AFNETWORKING有一个很棒的图像加载器,但不是你需要的,因为图像在捆绑。

也许你可以试试SDWebImage 。 它也是一个xamarin 组件 ,它使用自动caching过期处理来实现asynchronous图像下载和asynchronous内存和磁盘映像caching。 使用它可能意味着扔掉很多硬编码的代码,但它可能是值得的,加上你的代码会变得更简单。 在iOS中,您还可以在控制器的viewDidLoad中设置一个SDWebImageManager

 - (void)viewDidLoad{ ... SDWebImageManager *manager = [SDWebImageManager sharedManager]; manager.delegate = self; ... } 

并将视图控制器设置为委托。 然后,当下面的委托方法被调用时:

 - (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL 

您可以在caching图像之前将图像缩放到适当的大小。

希望有所帮助。

我有一个类似的问题,我的卷轴不顺畅。 我在表格中插入一个variablesUIImageView与labelViews。 我所做的是改变方法HeightforRowAtIndexPath estimatedHeightforRowAtIndexPath现在滚动是光滑的。

    Interesting Posts