關於使用uitableview 中cell 來實現uiimageview的複用和圖片的異步加載

apple sample lazytableimageshtml

1,首先設置橫向顯示的uitableviewios

    self.customTableview.transform = CGAffineTransformMakeRotation(M_PI/-2);
同時須要將cell也加以旋轉不然其內部的圖片是反的app

        cell.contentView.transform = CGAffineTransformMakeRotation(M_PI/2);
2,使用cell的imageview來實現圖片的加載iphone

        cell.imageView.image = [UIImage imageNamed:@"timeline_image_loading@2x.png"];async

       這裏須要給imageview首先添加佔位的圖片,不然的話當滾動時後面的cell會由於複用而加載前面已經顯示的image
        cell.imageView.frame = CGRectMake(0.0f, 0.0f, cell.frame.size.width, self.customTableview.frame.size.height);
3,判斷下載圖片ide

if (!self.record.appIcon)
            {
                {
                    //if the user does not dragging the scroll view then will start the download
                    if (self.customTableview.dragging == NO && self.customTableview.decelerating == NO)
                    {
                        NSString *startURL = self.record.photoURL;
                        //start the download if the image url is no tempty
                        if (startURL && (NSNull*)startURL != [NSNull null])
                        {
                            NSString *endURL = [NSURL URLWithString:startURL];
                            if (endURL)
                            {
                                [self startIconDownload:self.record  withButtonWidth:self.customTableview.frame.size.width andButtonHeight:self.customTableview.frame.size.height forButtonIndex:indexPath.row andIndexPath:indexPath];
                            }
                        }
                    }
                }
                
            }else
            {
                cell.imageView.image = self.record.appIcon;
                [cell.imageView setContentMode:UIViewContentModeScaleAspectFit]; //將裁剪好的圖片以指定的大小顯示出來
            }
            
- (void)startIconDownload:(PhotosRecord *)appRecord withButtonWidth:(float)width andButtonHeight:(float)height forButtonIndex:(int)tag andIndexPath:(NSIndexPath *)indexPath{
    PhotosDetailDownloader*iconDownloader = [self.imageDownloadsInProgress objectForKey:indexPath];;
    
    if (iconDownloader == nil)
    {
        iconDownloader = [[PhotosDetailDownloader alloc] init];
        iconDownloader.kids = appRecord;
        [iconDownloader setAlbumPhotosDownloadCompletionHandler:^{
            // Display the newly loaded image
            if (appRecord.appIcon){
                NSLog(@"downloaded index here is %d",indexPath.row);
                UITableViewCell *cell = [self.customTableview cellForRowAtIndexPath:indexPath];
                
                cell.imageView.image = appRecord.appIcon;
                [cell.imageView setContentMode:UIViewContentModeScaleAspectFit];
                [cell setNeedsLayout]; //這句很重要,不然下載成功後的首個cell和其後已經在屏幕中顯示的cell的image沒法顯示出來。關於這點詳見下面的回覆
                [self.imageDownloadsInProgress removeObjectForKey:indexPath];
            }
            
            // Remove the IconDownloader from the in progress list.
            
        }
         ];
        //防止圖片重複下載?
        if (iconDownloader) {
            [self.imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
            
        }
        [iconDownloader startDownloadWithWidth:width andHeight:height];
        [iconDownloader release];
    }
    
}

oop

I am experimenting in tableView:cellForRowAtIndexPath to set an image by callingpost

[self downloadImage:urlString andSetIntoCellImageView:cell]

and in downloadImage, it will call NSURLConnection:sendAsynchronousRequest (iOS 5 and up only), and in the completion block, set the image by usingui

cell.imageView.image =[UIImage imageWithData:data];// data is downloaded data

and it works if in tableView:cellForRowAtIndexPath, the imageView is populated with a dummy placeholder image -- and I wonder how the new image is refreshed, is it by setNeedsDisplay to do a repaint? But if I don't set the placeholder image, then the new image won't show at all. I wonder what mechanism can be used to make it show the image?this

If I use

[cell.imageView setNeedsDisplay]

or

[cell setNeedsDisplay];

in the completion block, it won't work, and if I use

[self.table reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];

in the completion block by making downloadImage accept the indexPath, it will call tableView:cellForRowAtIndexPath again, and cause an infinite loop. So it seems like I need to use some hash table to remember if the image is already in hash table: if not, call downloadImage, and if in hash table, simply use it, so there will be no infinite loop.

But is there an easy way to cause the image to show up? Setting a placeholder image works but what if we don't -- by what mechanism does placeholder cause the refresh of image?

share | edit
 
   
So cell.imageView.image = [UIImage imageWithData:data] works as long as there's been a placeholder image set in the cell within the tableView:cellForRowAtIndexPath: method, but if you don't provide a placeholder, this same technique doesn't work? Would you mind posting how you're setting up the placeholder image? –  Carl Veazey Aug 31 '12 at 5:34
   
@CarlVeazey that's correct. Sure, I set the placeholder using cell.imageView.image = [UIImage imageNamed:@"pic0.png"]; –  動靜能量 Aug 31 '12 at 5:44
add comment

2 Answers

up vote 5 down vote accepted

When a UITableViewCell's -layoutSubviews method is called, if its imageView's image property is nil, imageView is given a frame of (0,0,0,0). Also, -layoutSubviews only is to be called in some situations: when the cell is about to become visible and when it is selected. Not during normal scrolling. So what you've seen is that setting the placeholder inside tableView:cellForRowAtIndexPath: sizes cell.imageView to a non-zero size and subsequent changes of the image will be visible.

I fixed the issue by calling [cell setNeedsLayout] in the completion handler, like so:

NSURLRequest*request =[NSURLRequest requestWithURL:[NSURL URLWithString:MY_IMAGE_URL]];[NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue completionHandler:^(NSURLResponse*response,NSData*data,NSError*error){[[NSOperationQueue mainQueue] addOperationWithBlock:^{UIImage*image =[UIImage imageWithData:data]; cell.imageView.image = image;[cell setNeedsLayout];}];

I found the completion block happens in the background so that necessitates performing my UI work on the main thread. Of course this solution won't account for cell reuse and so forth, but at least solves why the cell's image wouldn't appear :)

Hope this helps!

相關文章
相關標籤/搜索