本文参考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];
}