我已经阅读了很多关于不良滚动的UICollectionView帖子,但似乎都没有直接应用,或者它们仍然没有答案。
我正在使用AFNetworking
将图像(95px平方)异步加载到每个单元格上,然后当图像再次滚动到视图中时,图像将从缓存中恢复(由响应代码验证为0而不是200)。
这是我尝试过的:
weakCell.photoView.image = image;
因此图像不会在屏幕上绘制,滚动更平滑(在HTTP获取期间仍然有点结果)cellForRowAtIndexPath
方法删除了所有AFNetworking代码,滚动更加顺畅(即使屏幕上仍然显示自定义单元格阴影等)为了提高滚动效果,我有什么办法可以改进下面的代码吗?
这是我的手机代码:
#import "PhotoGalleryCell.h"
@implementation PhotoGalleryCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Setup the background color, shadow, and border
self.backgroundColor = [UIColor colorWithWhite:0.25f alpha:1.0f];
self.layer.borderColor = [UIColor blackColor].CGColor;
self.layer.borderWidth = 0.5f;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowRadius = 3.0f;
self.layer.shadowOffset = CGSizeMake(0.0f, 2.0f);
self.layer.shadowOpacity = 0.5f;
// Make sure we rasterize for retina
self.layer.rasterizationScale = [UIScreen mainScreen].scale;
self.layer.shouldRasterize = YES;
// Add to the content view
self.photoView = [[UIImageView alloc] initWithFrame:self.bounds];
[self.contentView addSubview:self.photoView];
}
return self;
}
- (void)prepareForReuse
{
[super prepareForReuse];
self.photoView.image = nil;
self.largeImageURL = nil;
}
这是我的UICollectionView代码:
#pragma mark - Collection View Delegates
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [zePhotos count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
PhotoGalleryCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kPGPhotoCellIdentifier forIndexPath:indexPath];
// Get a reference to the image dictionary
NSDictionary *photoDict = [[zePhotos objectAtIndex:indexPath.row] objectForKey:@"image"];
// Asynchronously set the thumbnail view
__weak PhotoGalleryCell *weakCell = cell;
NSString *thumbnailURL = [[photoDict objectForKey:@"thumbnail"] objectForKey:@"url"];
NSURLRequest *photoRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:thumbnailURL]];
[cell.photoView setImageWithURLRequest:photoRequest
placeholderImage:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
weakCell.photoView.image = image;
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(@"Error retrieving thumbnail... %@", [error localizedDescription]);
}];
// Cache the large image URL in case they tap on this cell later
cell.largeImageURL = [[photoDict objectForKey:@"large"] objectForKey:@"url"];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:@"showPhotoDetail" sender:self];
}
答案 0 :(得分:1)
你可以尝试将shadowPath添加到你的单元init中,它应该提高性能,这是我在我的一个项目中使用的代码,用于添加一个舍入的shadowPath(有关更多选择,请参阅UIBezierPath方法)
self.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:self.frame.bounds
byRoundingCorners:UIRectCornerAllCorners
cornerRadii:CGSizeMake(10, 10)].CGPath;
此外,如果我没记错AFNetworking没有调整从服务器返回的图像的大小,所以它可能会影响图像的质量(尽管你添加到UIImageView的缩放方法),我建议调度返回的图像如果你愿意,可以调整它的大小:
CGSize targetSize = cell.photoView.bounds.size;
[cell.photoView setImageWithURLRequest:photoRequest
placeholderImage:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CGFloat imageHeight = image.size.height;
CGFloat imageWidth = image.size.width;
CGSize newSize = weakCell.imageView.bounds.size;
CGFloat scaleFactor = targetSize.width / imageWidth;
newSize.height = imageHeight * scaleFactor;
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *small = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
dispatch_async(dispatch_get_main_queue(),^{
weakCell.photoView.image = small;
});
});
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(@"Error retrieving thumbnail... %@", [error localizedDescription]);
}];
答案 1 :(得分:0)
代码检查看起来不错,但我敢打赌它是阴影的合成,这为滞后增加了很多。你弄清楚究竟是什么导致延迟的方法是使用仪器中的Time Profiler工具。 Here are the docs from Apple。
答案 2 :(得分:0)
问题是,当您快速滚动时,您同时启动了数百个网络请求。如果缓存了图像,请立即显示。如果不这样做,只在表视图速度变慢时才开始下载。
您可以使用以下内容:
//Properties or Instance Variables
NSDate *scrollDateBuffer;
CGPoint scrollOffsetBuffer;
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSTimeInterval secondsSinceLastScroll = [[NSDate date] timeIntervalSinceDate:scrollDateBuffer];
CGFloat distanceSinceLastScroll = fabsf(scrollView.contentOffset.y - scrollOffsetBuffer.y);
BOOL slow = (secondsSinceLastScroll > 0 && secondsSinceLastScroll < 0.02);
BOOL small = (distanceSinceLastScroll > 0 && distanceSinceLastScroll < 1);
if (slow && small) {
[self loadImagesForOnscreenRows];
}
scrollDateBuffer = [NSDate date];
scrollOffsetBuffer = scrollView.contentOffset;
}
您需要在其他方法中调用loadImagesForOnscreenRows
,例如新数据进入时,viewWillAppear
和scrollViewDidScrollToTop
。
以下是loadImagesForOnscreenRows
的示例实现:
- (void)loadImagesForOnscreenRows
{
@try {
for (UITableViewCell *cell in self.tableView.visibleCells) {
// load your images
NSURLRequest *photoRequest = …;
if (photoRequest) {
[cell.photoView setImageWithURLRequest:…];
}
}
}
@catch (NSException *exception) {
NSLog(@"Exception when loading table cells: %@", exception);
}
}
我在try / catch块中有这个,因为根据我的经验[UITableView -visibleCells]
不可靠 - 它偶尔会返回没有超级视图的解除分配的单元格或单元格。如果确保仅在表不能快速滚动时调用此方法,则不应过多影响滚动性能。
另请注意,AFNetworking UIImageView类别不会公开缓存对象。您需要稍微修改它以检查您是否已经缓存了图像; this answer应该指出正确的方向。