繁体   English   中英

UITableView滚动不流畅

[英]UITableView scrolling is not smooth

我在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中编写的应用程序也有同样的问题。

平滑滚动测试应用程序

您是否每个人都尝试使用一个保存在Bundle 120x120图像来填充您的TableView 这样,您可以检查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;

}

试试facebook的异步显示库。

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实体,并定义所需的任何属性(数据变量)。 您需要定义两个“可转换”属性,一个用于照片,另一个用于缩略图。

然后在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处理所有内存管理。

祝好运!

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

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

这两个技巧让我的桌子流得非常好。 我从API服务获取图像数据,AFNETWORKING有一个很棒的图像加载器,但由于图像在捆绑中,所以不需要。

也许你可以试试SDWebImage 它也是一个xamarin 组件 ,它通过自动缓存到期处理来简化异步映像下载器和异步内存以及磁盘映像缓存。 使用它可能意味着丢弃大量硬编写的代码,但它可能是值得的 - 你的代码将变得更加简单。 在iOS中,您还可以在控制器的viewDidLoad中设置SDWebImageManager

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

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

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

您可以在缓存之前将图像缩放到适当大小的拇指。

希望有所帮助。

Weel我有类似的问题,我的卷轴不顺畅。 我在表中插入一个带有内部labelViews的变量UIImageView。 我所做的是为estimatedHeightforRowAtIndexPath更改方法HeightforRowAtIndexPath,现在滚动是平滑的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM