2013年9月11日 星期三

iOS 使用SDWebImage在table view載入不同高度圖片

From Evernote:

iOS 使用SDWebImage在table view載入不同高度圖片

前言
剛開始我有種困擾,
我希望用table view的方式載入圖片。
下載方式既是非同步,
每個table view cell還要依據圖片大小來調整高度。
這…這...我一度有打算放棄,
改用scroll view來實作~

困境
但是一想到最基本的scroll view實作方式,
就是在create content時指定好frame的大小及內容來源。
也就是說,如果我有100張圖片,豈不要發100個requests!
網路接口都被我塞爆了,再者高度也無法事先取得阿!

咦~其實有比較高明的作法,
我只載入前後幾張圖,loading總比較輕了吧。
不過通常都實作在有paging的情況下(就是一頁一頁翻的效果)
這沒法子恣意滑來滑去。

那我就取消paging限制讓他滑來滑去阿~
可是問題又來了,
scroll view content一直被我切換的狀況下,
request還是無止境的一直發,圖片load下來的效果讓我很擔憂阿。

實作
我是沒用scroll view下去實作試試看,
著眼的還是table view的特性,
就是user滑動過程,只有看得到的部分才會進行繪製

1
- (UITableViewCell*)tableView:(UITableView*)tableViewcellForRowAtIndexPath:(NSIndexPath*)indexPath

這樣可以減輕大部分loading,但是還有圖片高度阿!
很窩心的是stackoverflow上也有類似的提問 ( 連結在此 )

重點就是 以image url為key將圖片高度存起來
然後在設定cell高度的function去判斷

1
2
3
4
5
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *idxKey = [imageArray objectAtIndex:indexPath.row];
    CGFloat height = [[[NSUserDefaults standardUserDefaults] objectForKey:idxKey] floatValue];
    return (height < 1) ? 240 : height;
}

回頭看一下SDWebImage這邊要怎麼用好了。
可以到 GitHub 下載,MIT License

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 [cell.imageView setImageWithURL:[NSURL URLWithString:urlKey]
                   placeholderImage:nil
                          completed:^(UIImage *image, NSError *err, SDImageCacheType typ) {
                                  [activityIndicator removeFromSuperview];
                                  // save height of an image to some cache
                                  [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithFloat:image.size.height * 320 / image.size.width]
                                                                            forKey:urlKey];
                                  if ([record containsObject:[NSString stringWithFormat:@"%d",indexPath.row]]) {
                                      NSLog(@"index:%d record already have it! curr is %d", indexPath.row, currentLoadingIndexPath.row);
                                  } else {
                                     //animation effect seems not good enough...
                                      //[tableView beginUpdates];
                                      //[tableView reloadRowsAtIndexPaths:@[indexPath]
                                      //                 withRowAnimation:UITableViewRowAnimationFade];
                                      //[tableView endUpdates];
                                      [mainTable reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
                                      [record addObject:[NSString stringWithFormat:@"%d",indexPath.row]];
                                  }
                                 
                          }];
               
        return cell;
}

在completed底下寫個block
o 移除activityIndicator。 (這轉圈圈的效果稍後補充一下)
o 把image的高度用url當key記錄起來。
o 建一個array (record)把 完成loading image的indexPath.row給記起來
   這樣的用意是為了不希望每次都重畫整個table view。
o 註解掉update特定table cell的原因是我試起來的效果不好。

補充
如果想讓SDWebImage的placeholder放一個轉圈圈的效果,
比較快的作法是把 activityIndicator放在cell.contentView 上面。

1
2
3
4
__block UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.center = CGPointMake(160, 120);
[cell.contentView insertSubview:activityIndicator atIndex:999];
[activityIndicator startAnimating];

不用試cell.imageView了,我花了很多力氣,都沒成功 :(
希望這樣可以順便幫到一些忙~

沒有留言:

張貼留言

內容回應