当单元格具有 UIImageView 子视图时,UITableView 经历断断续续的滚动

Posted

技术标签:

【中文标题】当单元格具有 UIImageView 子视图时,UITableView 经历断断续续的滚动【英文标题】:UITableView experiences choppy scrolling when cell has a UIImageView subview 【发布时间】:2012-02-06 11:39:24 【问题描述】:

这让我在一天中的大部分时间都快疯了。

我有一个带有 UIImageViews 的 UITableView。这些图像视图在 tableview 的 cellForRow 函数中加载本地保存的 PNG 文件,这可以正常工作,只是当带有图像的单元格滚动到视线中时,tableview 将停止滚动几分之一秒。我已经在 *** 和谷歌上搜索了答案,但我的回答很短 - 所以任何帮助都将不胜感激。

这是我的 CellForRow 函数代码:

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


    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];



    if (cell == nil) 
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MyIdentifier"] autorelease];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    

    if([currSection isEqualToString:@"composer"])

        MySlide *s = [slidesArray objectAtIndex:indexPath.row];

        cell.textLabel.hidden = YES;
        UIImageView *whiteView = [[UIImageView alloc] initWithFrame:CGRectMake((projectsTable.frame.size.width/2)-150, 4, 204.8, 153.6)];

        if([s.slideImage isEqualToString:@""] || s.slideImage == nil)
            //no custom image in this cell - go with default background image

            whiteView.image = [UIImage imageNamed:@"cellback2.png"];
            whiteView.backgroundColor = [UIColor whiteColor];
        else
            cell.layer.shouldRasterize = YES;
            cell.layer.rasterizationScale = [UIScreen mainScreen].scale;

            NSData *data = [[NSData alloc] initWithContentsOfFile:s.slideImage];

            UIImage *im = [[UIImage alloc] initWithData:data];


            whiteView.image = im;

            whiteView.image = [self imageWithImage:whiteView.image CovertToSize:CGSizeMake(204.8,153.6)];
            whiteView.backgroundColor = [UIColor whiteColor];

        


        [cell.contentView addSubview:whiteView];

        [whiteView release];



        cell.accessoryType = UITableViewCellAccessoryNone;

    


  return cell;  

【问题讨论】:

发生这种情况的原因是每次创建新单元格、分配图像视图、格式化和添加.. 我忘了提到我已经尝试在 if(cell == nil) 语句中设置 whiteBack,但是在向滑动对象。请给我一个简单的例子来说明你将如何解决这个问题? 检查我的回答代码,我已经更新了.. 【参考方案1】:

需要进行一些更改,首先应该在生成单元格时添加UIImageViews,而不是每次点击tableView:cellForRowAtIndexPath:(正如@Vishy 建议的那样)。其次,您应该缓存从文档目录加载的图像([UIImage imageNamed:] 会自动为捆绑资源执行此操作)。

@interface MyViewController () 

    NSMutableDictionary *_imageCache;


@end


@implementation MyViewController

- (void)viewDidLoad 
    [super viewDidLoad];

    // other viewDidLoad stuff...

    _imageCache = [[NSMutableDictionary alloc] init];


- (void)viewDidUnload 
    [super viewDidUnload];

    // other viewDidUnload stuff...

    [_imageCache release];
    _imageCache = nil;


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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];

    if (cell == nil) 
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MyIdentifier"] autorelease];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

        UIImageView *whiteView = [[UIImageView alloc] initWithFrame:CGRectMake((projectsTable.frame.size.width/2)-150, 4, 204.8, 153.6)];
        whiteView.tag = 111;
        whiteView.backgroundColor = [UIColor whiteColor];

        [cell.contentView addSubview:whiteView];

        [whiteView release];
        cell.accessoryType = UITableViewCellAccessoryNone;
        cell.textLabel.hidden = YES;
    

    UIImageView* iView = (UIImageView*) [cell.contentView viewWithTag:111];


    if([currSection isEqualToString:@"composer"]) 

        MySlide *s = [slidesArray objectAtIndex:indexPath.row];

        if([s.slideImage isEqualToString:@""] || s.slideImage == nil) 

            //no custom image in this cell - go with default background image
            iView.image = [UIImage imageNamed:@"cellback2.png"];
        
        else 

            cell.layer.shouldRasterize = YES;
            cell.layer.rasterizationScale = [UIScreen mainScreen].scale;

            // use the image path as the cache key
            UIImage *theImage = [_imageCache objectForKey:s.slideImage];
            if (theImage == nil) 

                // load the image and save into the cache
                theImage = [UIImage imageWithContentsOfFile:s.slideImage];
                theImage = [self imageWithImage:theImage CovertToSize:CGSizeMake(204.8, 153.6)];

                [_imageCache setObject:theImage forKey:s.slideImage];
            

            iView.image = theImage;
           
    


@end

一般来说,tableView:cellForRowAtIndexPath: 是一种您需要退出快速的方法,因此应尽可能避免从磁盘加载图像。

【讨论】:

谢谢 - 这也有效,并且在处理比我目前允许我的用户添加到幻灯片中的更多图像时肯定会派上用场。【参考方案2】:

如下修改代码...

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];

if (cell == nil) 

    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MyIdentifier"] autorelease];
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    UIImageView *whiteView = [[UIImageView alloc] initWithFrame:CGRectMake((projectsTable.frame.size.width/2)-150, 4, 204.8, 153.6)];
    whiteView.tag = 111;
    whiteView.backgroundColor = [UIColor whiteColor];

    [cell.contentView addSubview:whiteView];

    [whiteView release];
    cell.accessoryType = UITableViewCellAccessoryNone;
    cell.textLabel.hidden = YES;



UIImageView* iView = (UIImageView*) [cell.contentView viewWithTag:111];


if([currSection isEqualToString:@"composer"])

    MySlide *s = [slidesArray objectAtIndex:indexPath.row];

    if([s.slideImage isEqualToString:@""] || s.slideImage == nil)
    
        //no custom image in this cell - go with default background image

        iView.image = [UIImage imageNamed:@"cellback2.png"];
    
    else
    
        cell.layer.shouldRasterize = YES;
        cell.layer.rasterizationScale = [UIScreen mainScreen].scale;

        iView.image = [UIImage imageWithContentsOfFile:s.slideImage];
        iView.image = [self imageWithImage:iView.image CovertToSize:CGSizeMake(204.8,153.6)];

       
  

【讨论】:

当单元格从 Documents 文件夹加载图像时,滚动仍然会停止一段时间。这个停止是否与图像数据的实际加载相关联?原始图像为 1024x768,但正如您从我的代码中看到的那样,已调整大小以与单元格的大小相对应 - 这是否可能导致停止? @PinkFloydRocks 您还需要缓存图像,将它们存储在UIViewController 子类中的NSArrayNSDictionary 中(在调整它们大小之后)。 @EllNeal 我通过生成缩略图以及幻灯片的主图像来实现它。所以可能是图像的大小及其数据导致了停止。但是出于好奇,您能否提供一个如何缓存图像的小示例?您是否将他们的数据缓存在数组中并在创建图像时使用这些数据? @PinkFloydRocks 我会发布答案【参考方案3】:

每个 UIImage 第一次显示时也会有延迟。有关在缓存时间而不是显示时间提示工作的详细信息,请参阅此帖子:

Setting image property of UIImageView causes major lag

【讨论】:

以上是关于当单元格具有 UIImageView 子视图时,UITableView 经历断断续续的滚动的主要内容,如果未能解决你的问题,请参考以下文章

为啥当我在平移单元格时更改 UIImageView 的图像时,整个视图会重置一秒钟?

为单元格的子视图实现不同的用户交互功能

自定义单元格中的 UIImageView 无法正常工作

为啥自调整大小的表格视图单元格中的 UIImageView 具有内容模式 AspectFit 的原始高度?

指定视图大小何时取决于多个子视图的约束

选择 tableviewcell 时如何运行函数(例如,按下单元格时更新 UIImageView)