关于使用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!

相关文章
相关标签/搜索