前言
上一篇文章里我們已經(jīng)將圖片選擇器的基本功能完成了文兑。相冊里圖片比較多的小伙伴有沒有覺得上下滾動起來不是很順呢(當(dāng)然夕膀,像小編這種屌絲挫男可能不會有這煩惱,相冊空空如也园爷,沒有自拍就沒有噩夢),那怎么來處理這種同時(shí)請求巨巨巨巨巨多圖片的情況呢,這里Apple API里給我們指了條路(蹩腳英文得派上場了LOOOOOOOOOOL)
如果需要同時(shí)加載多個(gè)資源的圖片數(shù)據(jù)宪潮,使用PHCachingImageManager類通過加載你馬上想要的圖片來“預(yù)加載”緩存。打個(gè)比方戈抄,在一個(gè)顯示圖片資源縮略圖的collection view內(nèi),你可以在滾動到當(dāng)前位置前就緩存好圖片后专。
使用這些類來請求有關(guān)Photos資源的圖片划鸽,視頻,活圖內(nèi)容戚哎。
Photos框架根據(jù)你的要求自動下載并生成圖片裸诽,緩存它們,為了更快的復(fù)用型凳。為了大量資源能更快地表現(xiàn)丈冬,你也可以批請求預(yù)加載圖片。
那現(xiàn)在的思路就是在UICollectionView滾動前甘畅,先緩存可能顯示的圖片殷蛇,也就是當(dāng)前可顯示區(qū)域前后將要顯示的圖片实夹。
開始
定義所需屬性
//緩存圖片管理器
@property (nonatomic, strong) PHCachingImageManager *imageManager;
//先前預(yù)加載區(qū)域,用于比較
@property CGRect previousPreheatRect;
更新緩存
- 判斷界面是否顯示
- 初始化預(yù)加載區(qū)域大小粒梦,在可顯示區(qū)域基礎(chǔ)上前后各增加半個(gè)可顯示區(qū)域
- 當(dāng)滾動范圍大于當(dāng)前顯示界面的三分之一時(shí),進(jìn)行緩存操作(由于此方法會在
scrollview
的代理方法scrollViewDidScroll:
中調(diào)用荸实,頻繁調(diào)用會影響性能匀们,這里的規(guī)則可以根據(jù)需求進(jìn)行調(diào)控) - 區(qū)別新增資源以及移除資源,進(jìn)行緩存更新
- (void)updateCachedAssets {
BOOL isViewVisible = [self isViewLoaded] && [[self view] window] != nil;
if (!isViewVisible) { return; }
// 預(yù)加載區(qū)域是可顯示區(qū)域的兩倍
CGRect preheatRect = self.collectionView.bounds;
preheatRect = CGRectInset(preheatRect, 0.0f, -0.5f * CGRectGetHeight(preheatRect));
// 比較是否顯示的區(qū)域與之前預(yù)加載的區(qū)域有不同
CGFloat delta = ABS(CGRectGetMidY(preheatRect) - CGRectGetMidY(self.previousPreheatRect));
if (delta > CGRectGetHeight(self.collectionView.bounds) / 3.0f) {
// 區(qū)分資源分別操作
NSMutableArray *addedIndexPaths = [NSMutableArray array];
NSMutableArray *removedIndexPaths = [NSMutableArray array];
[self computeDifferenceBetweenRect:self.previousPreheatRect andRect:preheatRect removedHandler:^(CGRect removedRect) {
NSArray *indexPaths = [self indexPathsForElementsInCollectionView:self.collectionView rect:removedRect];
[removedIndexPaths addObjectsFromArray:indexPaths];
} addedHandler:^(CGRect addedRect) {
NSArray *indexPaths = [self indexPathsForElementsInCollectionView:self.collectionView rect:addedRect];
[addedIndexPaths addObjectsFromArray:indexPaths];
}];
NSArray *assetsToStartCaching = [self assetsAtIndexPaths:addedIndexPaths];
NSArray *assetsToStopCaching = [self assetsAtIndexPaths:removedIndexPaths];
// 更新緩存
[self.imageManager startCachingImagesForAssets:assetsToStartCaching
targetSize:AssetGridThumbnailSize
contentMode:PHImageContentModeAspectFill
options:nil];
[self.imageManager stopCachingImagesForAssets:assetsToStopCaching
targetSize:AssetGridThumbnailSize
contentMode:PHImageContentModeAspectFill
options:nil];
// 存儲預(yù)加載矩形已供比較
self.previousPreheatRect = preheatRect;
}
}
- 此方法是區(qū)分增加的區(qū)域以及減少的區(qū)域
- (void)computeDifferenceBetweenRect:(CGRect)oldRect andRect:(CGRect)newRect removedHandler:(void (^)(CGRect removedRect))removedHandler addedHandler:(void (^)(CGRect addedRect))addedHandler {
if (CGRectIntersectsRect(newRect, oldRect)) {
CGFloat oldMaxY = CGRectGetMaxY(oldRect);
CGFloat oldMinY = CGRectGetMinY(oldRect);
CGFloat newMaxY = CGRectGetMaxY(newRect);
CGFloat newMinY = CGRectGetMinY(newRect);
if (newMaxY > oldMaxY) {
CGRect rectToAdd = CGRectMake(newRect.origin.x, oldMaxY, newRect.size.width, (newMaxY - oldMaxY));
addedHandler(rectToAdd);
}
if (oldMinY > newMinY) {
CGRect rectToAdd = CGRectMake(newRect.origin.x, newMinY, newRect.size.width, (oldMinY - newMinY));
addedHandler(rectToAdd);
}
if (newMaxY < oldMaxY) {
CGRect rectToRemove = CGRectMake(newRect.origin.x, newMaxY, newRect.size.width, (oldMaxY - newMaxY));
removedHandler(rectToRemove);
}
if (oldMinY < newMinY) {
CGRect rectToRemove = CGRectMake(newRect.origin.x, oldMinY, newRect.size.width, (newMinY - oldMinY));
removedHandler(rectToRemove);
}
} else {
addedHandler(newRect);
removedHandler(oldRect);
}
}
- (NSArray *)assetsAtIndexPaths:(NSArray *)indexPaths {
if (indexPaths.count == 0) { return nil; }
NSMutableArray *assets = [NSMutableArray arrayWithCapacity:indexPaths.count];
for (NSIndexPath *indexPath in indexPaths) {
PHAsset *asset = self.assetsFetchResults[indexPath.item];
[assets addObject:asset];
}
return assets;
}
- 此方法作用是獲取某區(qū)域內(nèi)元素的indexPaths
- (NSArray *)indexPathsForElementsInCollectionView:(UICollectionView *)collection rect:(CGRect)rect {
NSArray *allLayoutAttributes = [collection.collectionViewLayout layoutAttributesForElementsInRect:rect];
if (allLayoutAttributes.count == 0) { return nil; }
NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:allLayoutAttributes.count];
for (UICollectionViewLayoutAttributes *layoutAttributes in allLayoutAttributes) {
NSIndexPath *indexPath = layoutAttributes.indexPath;
[indexPaths addObject:indexPath];
}
return indexPaths;
}
- 界面顯示時(shí)需第一次更新緩存
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// 可見區(qū)域刷新緩存
[self updateCachedAssets];
}
- UICollectionView滾動時(shí)更新緩存
#pragma mark -- UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
[self updateCachedAssets];
}
上一篇我們實(shí)現(xiàn)了相冊變化的檢測准给,那么如果相冊資源變化了泄朴,緩存如何操作呢?
這里小編直接將緩存重置露氮,簡單粗暴~
- (void)resetCachedAssets {
[self.imageManager stopCachingImagesForAllAssets];
self.previousPreheatRect = CGRectZero;
}
是不是覺得已經(jīng)大功告成了祖灰?其實(shí)還有個(gè)很重要的地方要改,不然就白忙活了畔规!
在-collectionView:collectionView cellForItemAtIndexPath:
這個(gè)代理方法內(nèi)局扶,我們請求圖片使用的[PHImageManager defaultManager]
換成self.imageManager
。因?yàn)槲覀兪褂玫氖谴藢ο髞磉M(jìn)行一系列緩存操作的叁扫。
附上DEMO
結(jié)束語
這個(gè)簡單的選擇器功能還不夠完善三妈,主要是熟悉Photos框架,如果讀者感興趣的話莫绣,可以持續(xù)關(guān)注小編的ASImagePicker
ASImagePicker持續(xù)更新中...
https://github.com/alanshen0118/ASImagePicker
文章中有任何錯(cuò)誤希望讀者能積極指出畴蒲,我會及時(shí)更正。
如果喜歡对室,請持續(xù)關(guān)注模燥,順便點(diǎn)個(gè)喜歡噢??????幫五菱加加油~@_@