#前言 最近做的專案中遇到了自定義相簿這個需求,於是就搜尋到了Photos這個框架,說來慚愧。。這個是iOS8的東西,現在才用到。。由於網上的各種講解也很多,我就只講講裡面的遇到的坑和用法,當做筆記記錄一下吧
先來看一下效果圖
大概就是這樣的,點選按鈕獲取系統相簿資源,然後放到自定義的介面中,我們的專案底部需要加入預覽的scroll,然後就是大圖檢視,圖片回撥。。具體的程式碼裡面有詳細註釋。。
#好了,簡單粗暴,直接上關鍵程式碼 ##獲取相簿許可權
//相簿許可權判斷
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusDenied)
{
//相簿許可權未開啟
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
// app名稱
NSString *app_Name = [infoDictionary objectForKey:@"CFBundleDisplayName"];
[weakSelf SetAlertWithTitle:@"提醒" andMessage:[NSString stringWithFormat:@"請在iPhone的“設定->隱私->照片”開啟%@訪問你的手機相簿",app_Name]];
}
else if(status == PHAuthorizationStatusNotDetermined)
{
//相簿進行授權
/* * * 第一次安裝應用時直接進行這個判斷進行授權 * * */
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status)
{
//授權後直接開啟照片庫
if (status == PHAuthorizationStatusAuthorized)
{
dispatch_async(dispatch_get_main_queue(), ^
{
[weakSelf pushViewController];
});
}
}];
}
else if (status == PHAuthorizationStatusAuthorized)
{
[weakSelf pushViewController];
}
複製程式碼
##然後就是獲取系統相簿資源了
-(void) getSystemPhotos
{
// 獲取所有資源的集合,並按資源的建立時間排序
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
dispatch_async(dispatch_get_global_queue(0,0), ^{
// 獲得相機膠捲的圖片
PHFetchResult<PHAssetCollection *> *collectionResult1 = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
for (PHAssetCollection *collection in collectionResult1) {
if (![collection.localizedTitle isEqualToString:@"Camera Roll"]) continue;
[self searchAllImagesInCollection:collection];
break;
}
});
}
- (void)searchAllImagesInCollection:(PHAssetCollection *)collection
{
// 採取同步獲取圖片(只獲得一次圖片)
PHImageRequestOptions *imageOptions = [[PHImageRequestOptions alloc] init];
imageOptions.resizeMode = PHImageRequestOptionsResizeModeFast;
imageOptions.synchronous = YES;
imageOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
PHVideoRequestOptions *videoOptions = [[PHVideoRequestOptions alloc] init];
videoOptions.deliveryMode = PHVideoRequestOptionsDeliveryModeFastFormat;
__weak typeof (self) weakSelf = self;
// 遍歷這個相簿中的所有資源
PHFetchResult<PHAsset *> *assetResult = [PHAsset fetchAssetsInAssetCollection:collection options:nil];
for (PHAsset *asset in assetResult) {
if (weakSelf.isPhotoModel) {
// 過濾非圖片
if (asset.mediaType != PHAssetMediaTypeImage) continue;
PhotoModel *photo = [[PhotoModel alloc] init];
photo.asset = asset;
[_imgViewArr addObject:photo];
}
else
{
// 過濾非視訊
if (asset.mediaType != PHAssetMediaTypeVideo) continue;
PhotoModel *photo = [[PhotoModel alloc] init];
photo.asset = asset;
[_imgViewArr addObject:photo];
}
}
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf loadMainView];
});
}
複製程式碼
這裡有一個重點,就是獲取到的asset資源一定不要嘗試在這裡使用requestImageForAsset方法去獲得圖片資訊,特別是高清圖,一到真機上幾百張圖片載入記憶體暴增導致閃退,就算使用裁剪圖片或者PHImageRequestOptionsResizeModeFast模式,也會有一小段的空白時間,並不能進來後瞬間顯示圖片,所以此處我選擇直接將asset儲存進陣列中,利用collctionview的重用機制,在自定義的cell裡面再去使用requestImageForAsset載入,效果會好很多,自定義CollectionViewCell中的程式碼如下
-(void)loadPhotoData:(PhotoModel *)photo withTargetSize:(CGSize)target state:(BOOL)isPhotoModel
{
__weak typeof (self) weakSelf = self;
if (photo)
{
[[PHImageManager defaultManager] requestImageForAsset:photo.asset targetSize:CGSizeMake(200, 200) contentMode:PHImageContentModeAspectFit options:nil resultHandler:^(UIImage *result, NSDictionary *info){
//修正圖片方向
UIImage *targetImg = [weakSelf fixOrientation:result];
//縮小圖片
targetImg = [weakSelf reSizeImage:targetImg ForSize:target];
weakSelf.PhotoImg.image = targetImg;
photo.isPhotoModel = YES;
}];
if (!isPhotoModel) {
_bottom.hidden = NO;
PHImageManager *manager = [PHImageManager defaultManager];
[manager requestAVAssetForVideo:photo.asset options:nil resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info)
{
//CMTime轉換
NSTimeInterval total = CMTimeGetSeconds(asset.duration);
NSString *duration = [weakSelf stringWithTime:total];
//回到主執行緒
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.VideoDuration.text = duration;
photo.asset_video = asset;
photo.isPhotoModel = NO;
});
}];
}
}
}
複製程式碼
這段程式碼中還加入了是否為圖片模式的判斷,如果是選擇的視訊,則這個cell中就將視訊asset儲存到對應的key中,之後再通過AVPlayer去播放這個資源
#結尾 首先感謝網上各位大神的資料講解,我也看過好幾份例子。。GitHub上那幾個其實都有一點小問題(圖片回撥不全什麼的,希望大神看到不要見怪)。。不能滿足我們專案的需求,所以就自己擼了一個。。
目前我在使用Photos時遇到最大的一個坑就是上文中提到的記憶體暴增導致的閃退問題,一直嘗試著在外部獲取高清圖片再儲存進陣列,後來無意間發現利用collctionview的重用就解決了這個問題,GIF中的圖片回撥什麼的我就不一一列舉了,程式碼裡面我幾乎都註釋了,需要的可以去看看,覺得有用的話記得給個star吧~
PS:對了,我攝像頭拍照錄視訊的功能還沒加進來,如果有需要,時間充裕的話,我會盡量補上~
地址:GitHub
#更新 現已加入攝像頭拍照錄影功能、加入iOS9之後的collection長按拖動圖片功能、優化圖片選擇器中的卡頓現象,去除在collectioncell中繪製圖片程式碼,加快載入速度,以下程式碼已去除
//修正圖片方向
UIImage *targetImg = [weakSelf fixOrientation:result];
//縮小圖片
targetImg = [weakSelf reSizeImage:targetImg ForSize:target];
複製程式碼
真機測試效果更佳,大家用真機測試吧,程式碼都在GitHub中,註釋很詳細,大家可以去看,覺得有用記得點個star~