根据图片动态计算UITableViewCell的高度

本文参考http://www.tuicool.com/articles/iMNrAf 进行了整理

使用场景

UITableViewCell需要加载来自服务器的图片,cell的宽度一定,高度需要根据加载的图片动态调整。

难点

需要显示的图片来自服务器,只有图片加载完成以后才能知道图片的高度。

解决方法

1.图片异步加载完成以后更新cell的height,刷新tableview。
2.采用SDWebImage缓存已经加载过的图片。
3.在tableview处于滑动状态时不加载图片,不刷新tableview,tableview停止滑动时触发reloadData。
4.添加清空缓存空能,防止app占用太多的磁盘空间。

代码

//_cellHeights:保存所有cell高度的数组
//deatilContents:tableview的数据源
//配置cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *imageIdentifier = [NSString stringWithFormat:@"imageIdentifier_%ld",(long)indexPath.row];
    DetailImageCell *imageCell = [tableView dequeueReusableCellWithIdentifier:imageIdentifier];
    if (!imageCell) {
        imageCell = [[DetailImageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:imageIdentifier];
    }

    [self configureCell:imageCell atIndexPath:indexPath];
    return imageCell;
}

//根据获取的image高度设置cell高度,如果图片还没有加载成功,就先设置为默认图片,所有cell的高度都存在数组_cellHeights中
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    NSDictionary *dict = [deatilContents safeObjectAtIndex:indexPath.row];
    UIImage *img = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:[dict safeObjectForKey:@"photoUrl"]];
    if (!img) {
        img = [UIImage imageNamed:@"placeholder"];
    }
    CGFloat height = [DetailImageCell cellHeightWithImage:img];
    [_cellHeights replaceObjectAtIndex:indexPath.row withObject:[NSString stringWithFormat:@"%f",height]];

    return [[_cellHeights safeObjectAtIndex:indexPath.row] floatValue];
}

//pragma mark 设置带有图片的cell
-(void)configureCell:(DetailImageCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    NSDictionary *dict = [deatilContents safeObjectAtIndex:indexPath.row];
    NSString *imgURL = [dict safeObjectForKey:@"photoUrl"];
    UIImage *cachedImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:imgURL];

    if ( !cachedImage ) {
        //如果tableview正在滚动/滑动就先不加载图片,只有处于静止状态时才开始加载
        if ( !self.tableView.dragging && !self.tableView.decelerating ) {
            [self downloadImage:imgURL forIndexPath:indexPath];
        }
        //在图片没有加载完成之前,先用默认图片替代
        [cell setImage:[UIImage imageNamed:@"placeholder"] withHeight:[[_cellHeights safeObjectAtIndex:indexPath.row] floatValue]];
    } else {
      //缓存中拿到了需要加载的图片直接显示真实图片
        [cell setImage:cachedImage withHeight:[[_cellHeights safeObjectAtIndex:indexPath.row] floatValue]];
    }
}

//根据路径加载图片,加载完成后进行缓存,并刷新tableview
- (void)downloadImage:(NSString *)imageURL forIndexPath:(NSIndexPath *)indexPath
{
    weakSelf(weakSelf)
    [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:[NSURL URLWithString:imageURL]
                                                          options:SDWebImageDownloaderUseNSURLCache
                                                        progress:nil
                                                        completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished)
    {
        [[SDImageCache sharedImageCache] storeImage:image forKey:imageURL toDisk:YES];
        [weakSelf performSelectorOnMainThread:@selector(reloadCellAtIndexPath:)
                                withObject:indexPath waitUntilDone:NO];
    }];
}

//pragma mark - Scroll view delegate
// table view 停止拖动了,刷新tableview开始更新
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (!decelerate) {
        [self loadImageForOnScreenRows];
    }
}

// table view 停止滚动了
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self loadImageForOnScreenRows];
}

//节约性能,只加载当前显示在屏幕上的cell包含的image
- (void)loadImageForOnScreenRows
{
    NSArray *visiableIndexPathes = [self.tableView indexPathsForVisibleRows];

    for(NSInteger i = 0; i < [visiableIndexPathes count]; i++)
    {
        NSDictionary *dict = [deatilContents safeObjectAtIndex:i];
        NSString *imgURL = [dict safeObjectForKey:@"photoUrl"];
        if (imgURL) {
            [self downloadImage:imgURL forIndexPath:visiableIndexPathes[i]];
        }
    }
}

// 但是别认为调用 table view 的 reloadData 效率就不高,回顾下上面的步骤
// reloadData 实际上就是向代理要行数,要行高,对**显示出来**的 cell 填充数据
-(void)reloadCellAtIndexPath:(NSIndexPath *)indexpath
{
    [self.tableView reloadData];
}

//这个函数在需要清空磁盘的地方调用,一般都是类似于“我的”页面
-(void)clearDiskCache
{
   //获取当前磁盘缓存的大小
    self.cacheStr=[NSString stringWithFormat:@"%.2fM",[[SDImageCache sharedImageCache] getSize]/1024.0/1024.0];
    [[SDImageCache sharedImageCache] clearDisk];
}


你可能感兴趣的:(根据图片动态计算UITableViewCell的高度)