2015-08-16 77 views
4

我有一個UITableView,可以在UITableView中異步加載圖像。由於所有的圖像都是不同的高度,我根據圖像的高度設置了一個高度限制。在UITableView中使用Autolayout異步加載圖像

這工作正常,當我使用DataWithContentsOfUrl,但凍結了用戶界面。當我加載異步,圖像堆放在彼此的頂部上,像這樣:

http://i.stack.imgur.com/TEUwK.png

我使用的代碼如下:

NSURL * imageURL = [NSURL URLWithString:img]; 
NSURLRequest* request = [NSURLRequest requestWithURL:imageURL]; 
cell.imageViewHeightConstraint.constant=0; 
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * response, NSData * data, NSError * error) { 
    if (!error){ 
     UIImage *imgz = [UIImage imageWithData:data]; 
     [cell.CellImg setBackgroundImage:imgz forState:UIControlStateNormal]; 
     [cell.CellImg sizeToFit]; 
     cell.imageViewHeightConstraint.constant=result.width*(imgz.size.height/imgz.size.width); 
     [cell setNeedsUpdateConstraints]; 
    } 
}]; 
[cell updateConstraints]; 

當我向上和向下滾動一幾次圖像正確定位自己。

回答

0

雖然reloadRowsAtIndexPaths作品,它最終導致接口是緩慢和laggy,特別是當用戶滾動時。我的解決方案是一旦加載數據以遍歷對象id的https://graph.facebook.com/v2.1/%@/?access_token=%@&fields=attachments,然後將圖像高度尺寸存儲在數組中。然後,在cellForRowAtIndexPath中簡單地將cell.imageViewHeightConstraint.constant設置爲數組中的值。通過這種方式,所有的單元格高度都會在單元格加載完成後立即設置,並且一旦圖像加載完畢,圖像就可以完美地放置到位。

0

嘗試用約束不斷大致如下:

cell.imageViewHeightConstraint.constant=result.width*(imgz.size.height/imgz.size.width); 
[table reloadRowsAtIndexPaths:@[indexPathForCurrentCell] withRowAnimation:UITableViewRowAnimationNone]; 

您還可以設置動畫。

2

這個問題沒有爲變化的圖像大小指定所需的行爲。單元格應該適合高度還是單元格內的圖像視圖(看起來像代碼中的按鈕)?

但是我們應該暫時擱置這個問題並且研究代碼中更嚴重的問題:它會發出一個來自cellForRowAtIndexPath的無保護的網絡請求。結果,(a)用戶來回滾動會產生許多多餘的請求,並且(b)用戶快速長時間滾動會產生一個請求,當啓動它的單元消失時,該請求會被滿足 - 作爲單元重用換另一行。

爲了解決(a),數據源應該緩存提取的圖像,並只請求那些沒有收到的圖像。爲了解決(b),完成塊不應直接指向單元。

一個簡單的緩存是這樣的:

@property(strong,nonatomic) NSMutableDictionary *images; 

// initialize this when you initialize your model 
self.images = [@{} mutableCopy]; 

// move the network code into its own method for clarity 
- (void)imageWithPath:(NSString *)path completion:(void (^)(UIImage *, NSError *))completion { 
    if (self.images[indexPath]) { 
     return completion(self.images[indexPath], nil); 
    } 
    NSURL *imageURL = [NSURL URLWithString:path]; 
    NSURLRequest *request = [NSURLRequest requestWithURL:imageURL]; 
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 
     if (!error){ 
      UIImage *image = [UIImage imageWithData:data]; 
      self.images[indexPath] = image; 
      completion(image, nil); 
     } else { 
      completion(nil, error); 
     } 
    }]; 
} 

現在,我們先檢查中的cellForRowAtIndexPath緩存中的圖像修復多個請求的問題。

UIImage *image = self.images[indexPath]; 
if (image) { 
    [cell.CellImg setBackgroundImage:image forState:UIControlStateNormal]; 
} else { 
    // this is a good place for a placeholder image if you want one 
    [cell.CellImg setBackgroundImage:nil forState:UIControlStateNormal]; 
    // presuming that 'img' is a string from your mode 
    [self imageWithPath:img completion:^(UIImage *image, NSError *error) { 
     // the image is ready, but don't assign it to the cell's subview 
     // just reload here, so we get the right cell for the indexPath 
     [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 
    }]; 
} 

還要注意在完成塊做了什麼......我們被不是指電池固定單元複用。相反,知道圖像現在被緩存,我們重新加載indexPath。

返回圖片大小:大多數應用程序喜歡看到表格視圖單元格與可變高度子視圖一起變得更高或更短。如果是這樣的話,那麼你就不應該在該子視圖上放置高度限制。相反,將其頂部和底部邊緣限制在單元格的內容視圖中(或將其包含在一系列子視圖中,這些子視圖互相約束頂部和底部,幷包含頂部和底部的子視圖頂部和底部的子視圖)。然後(在iOS 5以上,我認爲),這將讓你的細胞與子視圖約束鏈改變HIGHT ...

self.tableView.rowHeight = UITableViewAutomaticDimension; 
self.tableView.estimatedRowHeight = // your best guess at the average height here 
+0

我確實在那裏有一個NSCache,只是沒有顯示它,因爲我不認爲這是錯誤背後的原因。 – user2760706