????????有沒(méi)有人和我一樣来庭,在最開(kāi)始接觸iOS開(kāi)發(fā)的時(shí)候稍味,碰到圖片選擇器用的是UIImagePickerController删咱,后來(lái)發(fā)現(xiàn)產(chǎn)品和設(shè)計(jì)不會(huì)按照系統(tǒng)頁(yè)面來(lái)設(shè)計(jì)杖小,這個(gè)時(shí)候去github或者cocochina上找一個(gè)第三方庫(kù),修修改改碾阁,用到哪改到哪输虱,管中窺豹,由于定制了計(jì)劃脂凶,每月寫兩篇博客宪睹,借此機(jī)會(huì),把這個(gè)框架梳理一下蚕钦。
????????首先明確一點(diǎn)亭病,這篇文章是了解一下 AssetsLibrary和Photos框架,并就實(shí)例進(jìn)行說(shuō)明解析嘶居,很簡(jiǎn)單的一個(gè)小demo罪帖,并不是現(xiàn)成拿過(guò)來(lái)直接就能用。(Photos雖然比AssetsLibrary用起來(lái)舒服太多邮屁,但是它是iOS8.0之后才出來(lái)的整袁,注意一下適配)
????????市場(chǎng)上絕大部分圖片選擇器都大同小異,例如微信和微博:
其實(shí)就是兩個(gè)列表佑吝,一個(gè)相冊(cè)列表坐昙,一個(gè)圖片列表,當(dāng)然也可以直接理解為一個(gè)tableView芋忿,一個(gè)collectionView炸客。
Photos
1.1、UITableView
-
授權(quán)盗飒、獲取相冊(cè)集合
/*
* 獲取用戶授權(quán)
*
* PHAuthorizationStatus 授權(quán)狀態(tài)
*/
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
/*
* PHAuthorizationStatusNotDetermined 用戶還沒(méi)有進(jìn)行授權(quán)操作
* PHAuthorizationStatusRestricted 用戶關(guān)閉了訪問(wèn)相冊(cè)的權(quán)限
* PHAuthorizationStatusDenied 拒絕用戶訪問(wèn)這個(gè)應(yīng)用程序有明確的圖片數(shù)據(jù)
* PHAuthorizationStatusAuthorized 用戶已授權(quán)
*/
if (status == PHAuthorizationStatusNotDetermined || status == PHAuthorizationStatusRestricted) {
/*
* 未通過(guò)用戶授權(quán),可彈出用戶引導(dǎo)嚷量,UIAlertView(請(qǐng)?jiān)谠O(shè)備的\"設(shè)置-隱私-照片\"中允許訪問(wèn)照片)
*/
} else {
/*
* 用戶已授權(quán)
*
* 獲取相冊(cè)集合,將其加入到tableView數(shù)據(jù)源中
*/
PHFetchResult *album = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum
subtype:PHAssetCollectionSubtypeAlbumRegular
options:nil];
[album enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
PHAssetCollection *collection = (PHAssetCollection *)obj;
// 這里需要注意下逆趣,我們數(shù)據(jù)源中存的是PHAssetCollection
[self.groups addObject:collection];
[self.tableView reloadData];
}];
}
}];
-
信息對(duì)照表
屬性 | 描述 |
---|---|
PHAsset | 代表照片庫(kù)中的一個(gè)資源,通過(guò) PHAsset 可以獲取和保存資源 |
PHFetchOptions | 獲取資源時(shí)的參數(shù)嗜历,可以傳 nil宣渗,即使用系統(tǒng)默認(rèn)值 |
PHAssetCollection | PHCollection 的子類,表示一個(gè)相冊(cè)或者一個(gè)時(shí)刻(例:最近刪除梨州,視頻列表痕囱,收藏等) |
PHFetchResult | 表示一系列的資源結(jié)果集合(此處是相冊(cè)集合),從PHCollection 的類方法中獲得 |
PHImageManager | 用于處理資源的加載暴匠,加載圖片的過(guò)程帶有緩存處理鞍恢,可以通過(guò)傳入一個(gè) PHImageRequestOptions 控制資源的輸出尺寸等規(guī)格(上面cell刷新時(shí)代碼) |
PHImageRequestOptions | 控制加載圖片時(shí)的一系列參數(shù) |
-
枚舉
typedef NS_ENUM(NSInteger, PHAssetCollectionType) {
PHAssetCollectionTypeAlbum = 1, // 從iTunes同步的相冊(cè),以及用戶在 Photos 中自己建立的相冊(cè)
PHAssetCollectionTypeSmartAlbum = 2, // 相機(jī)相冊(cè)
PHAssetCollectionTypeMoment = 3, // 自動(dòng)生成的時(shí)間分組的相冊(cè)
} PHOTOS_ENUM_AVAILABLE_IOS_TVOS(8_0, 10_0);
typedef NS_ENUM(NSInteger, PHAssetCollectionSubtype) {
// 用戶在 Photos 中創(chuàng)建的相冊(cè),也就是我所謂的邏輯相冊(cè)
PHAssetCollectionSubtypeAlbumRegular = 2,
// 使用 iTunes 從 Photos 照片庫(kù)或者 iPhoto 照片庫(kù)同步過(guò)來(lái)的事件
PHAssetCollectionSubtypeAlbumSyncedEvent = 3,
// 使用 iTunes 從 Photos 照片庫(kù)或者 iPhoto 照片庫(kù)同步的人物相冊(cè)帮掉。
PHAssetCollectionSubtypeAlbumSyncedFaces = 4,
// 做了 AlbumSyncedEvent 應(yīng)該做的事
PHAssetCollectionSubtypeAlbumSyncedAlbum = 5,
// 從相機(jī)或是外部存儲(chǔ)導(dǎo)入的相冊(cè)
PHAssetCollectionSubtypeAlbumImported = 6,
// 用戶的 iCloud 照片流
PHAssetCollectionSubtypeAlbumMyPhotoStream = 100,
// 用戶使用 iCloud 共享的相冊(cè)
PHAssetCollectionSubtypeAlbumCloudShared = 101,
// 文檔解釋為非特殊類型的相冊(cè)弦悉,主要包括從 iPhoto 同步過(guò)來(lái)的相冊(cè)
PHAssetCollectionSubtypeSmartAlbumGeneric = 200,
// 相機(jī)拍攝的全景照片
PHAssetCollectionSubtypeSmartAlbumPanoramas = 201,
// 相機(jī)拍攝的視頻
PHAssetCollectionSubtypeSmartAlbumVideos = 202,
// 收藏文件夾
PHAssetCollectionSubtypeSmartAlbumFavorites = 203,
// 延時(shí)視頻文件夾,同時(shí)也會(huì)出現(xiàn)在視頻文件夾中
PHAssetCollectionSubtypeSmartAlbumTimelapses = 204,
// 包含隱藏照片或視頻的文件夾
PHAssetCollectionSubtypeSmartAlbumAllHidden = 205,
// 相機(jī)近期拍攝的照片或視頻
PHAssetCollectionSubtypeSmartAlbumRecentlyAdded = 206,
// 連拍模式拍攝的照片
PHAssetCollectionSubtypeSmartAlbumBursts = 207,
// 高速攝影慢動(dòng)作解析
PHAssetCollectionSubtypeSmartAlbumSlomoVideos = 208,
// 相機(jī)相冊(cè)蟆炊,所有相機(jī)拍攝的照片或視頻都會(huì)出現(xiàn)在該相冊(cè)中
PHAssetCollectionSubtypeSmartAlbumUserLibrary = 209,
// 前置攝像頭所拍攝的所有照片和視頻
PHAssetCollectionSubtypeSmartAlbumSelfPortraits PHOTOS_AVAILABLE_IOS_TVOS(9_0, 10_0) = 210,
// 所有的截圖
PHAssetCollectionSubtypeSmartAlbumScreenshots PHOTOS_AVAILABLE_IOS_TVOS(9_0, 10_0) = 211,
// 在可兼容的設(shè)備上使用景深攝像模式拍的照片
PHAssetCollectionSubtypeSmartAlbumDepthEffect PHOTOS_AVAILABLE_IOS_TVOS(10_2, 10_1) = 212,
// 包含所有的Live Photo資源
PHAssetCollectionSubtypeSmartAlbumLivePhotos PHOTOS_AVAILABLE_IOS_TVOS(10_3, 10_2) = 213,
PHAssetCollectionSubtypeSmartAlbumAnimated PHOTOS_AVAILABLE_IOS_TVOS(11_0, 11_0) = 214,
PHAssetCollectionSubtypeSmartAlbumLongExposures PHOTOS_AVAILABLE_IOS_TVOS(11_0, 11_0) = 215,
//包含所有類型
PHAssetCollectionSubtypeAny = NSIntegerMax
} PHOTOS_ENUM_AVAILABLE_IOS_TVOS(8_0, 10_0);
-
cell展示稽莉、賦值
- (void)refreshWithPHAssetCollection:(PHAssetCollection *)collection {
// 按時(shí)間生序
PHFetchOptions *option = [[PHFetchOptions alloc] init];
option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
/*
* 獲取相冊(cè)實(shí)體
*
* 根據(jù)實(shí)體拿到展示的三個(gè)屬性:標(biāo)題、圖片個(gè)數(shù)涩搓、相冊(cè)的第一張圖片
*/
PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:collection options:option];
self.textLabel.text = collection.localizedTitle;
self.detailTextLabel.text = [NSString stringWithFormat:@"%ld",[result count]];
[result enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
PHAsset *asset = (PHAsset *)obj;
PHImageRequestOptions *imageOption = [[PHImageRequestOptions alloc] init];
imageOption.resizeMode = PHImageRequestOptionsResizeModeFast;
/*
* 坑一 networkAccessAllowed
* 是否允許網(wǎng)絡(luò)訪問(wèn)污秆,默認(rèn)為NO
* 主要只是否可以從iCloud中下載圖像,如果iPhone開(kāi)啟iCloud優(yōu)化話存儲(chǔ)空間昧甘,設(shè)置為NO是拿不到圖片的良拼,這里也只一個(gè)坑,需要注意一下
*/
imageOption.networkAccessAllowed = YES;
/*
* 坑二 synchronous
* 是否同步處理一個(gè)圖像請(qǐng)求充边,默認(rèn)是NO
* 這里一般設(shè)置為NO将饺,requestImageForAsset 請(qǐng)求就會(huì)有兩次回調(diào)。第一次返回一個(gè)低質(zhì)量的圖片(縮略圖)痛黎,用于占位顯示予弧;第二次返回的是一個(gè)高質(zhì)量的圖(原圖)
* 如果設(shè)置為YES,請(qǐng)求就只有一次的回調(diào)湖饱,返回一個(gè)高質(zhì)量的圖(原圖)掖蛤,會(huì)有卡頓現(xiàn)象(線程阻塞)
*/
imageOption.synchronous = NO;
[[PHImageManager defaultManager] requestImageForAsset:asset
targetSize:CGSizeMake(100.0f, 100.0f)
contentMode:PHImageContentModeAspectFit
options:imageOption
resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
self.imageView.image = result;
}];
*stop = YES;
}];
}
-
相冊(cè)列表結(jié)果展示
1.2、UICollectionView
在上述表格中我們?cè)榻B過(guò)PHFetchOption井厌,它表示一個(gè)相冊(cè)集合蚓庭。
獲取collectionView的數(shù)據(jù)源其實(shí)很簡(jiǎn)單,與上述我們?cè)赾ell中獲取圖片封面一樣仅仆,通過(guò)PHAssetCollection就能拿到器赞。
// 照片按照時(shí)間生序排列
PHFetchOptions *option = [[PHFetchOptions alloc] init];
option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
// 獲取照片結(jié)果集合,將其添加至數(shù)據(jù)源數(shù)組
PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:self.colletion options:option];
[result enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
PHAsset *asset = (PHAsset *)obj;
[self.assets addObject:asset];
if (idx == result.count - 1) {
[self.collectionView reloadData];
}
}];
AssetsLibrary
2.1墓拜、TableView
-
獲取相冊(cè)集合
/** 代表整個(gè)設(shè)備中的資源庫(kù)(照片庫(kù) */
@property (nonatomic, retain) ALAssetsLibrary *assetsLibrary;
// 實(shí)例化一個(gè)對(duì)象
self.assetsLibrary = [[ALAssetsLibrary alloc] init];
// 獲取相冊(cè)
[self.assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (group) {
// 將相冊(cè)圖片張數(shù)不為零的添加到數(shù)據(jù)源中
if (group.numberOfAssets > 0) {
[_groups addObject:group];
}
} else {
[self.tableView reloadData];
}
} failureBlock:^(NSError *error) {
}];
-
更新cell
- (void)refresh:(ALAssetsGroup *)assetsGroup {
// 相冊(cè)封面賦值
size_t height = CGImageGetHeight(assetsGroup.posterImage);
float scale = height / 60.0f;
UIImage *groupImage = [UIImage imageWithCGImage:assetsGroup.posterImage
scale:scale
orientation:UIImageOrientationUp];
self.imageView.image = groupImage;
/*
* property
*
* ALAssetsGroupPropertyName 相冊(cè)的名字
* ALAssetsGroupPropertyType 相冊(cè)的類型
* ALAssetsGroupPropertyPersistentID 相冊(cè)的存儲(chǔ)id
* ALAssetsGroupPropertyURL 相冊(cè)存儲(chǔ)的位置地址
*/
self.textLabel.text = [assetsGroup valueForProperty:ALAssetsGroupPropertyName];
// 相冊(cè)圖片張數(shù)
self.detailTextLabel.text = [NSString stringWithFormat:@"%ld", (long)[assetsGroup numberOfAssets]];
self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
-
信息對(duì)照表
屬性 | 描述 |
---|---|
AssetsLibrary | 代表整個(gè)設(shè)備中的資源庫(kù)(照片庫(kù))港柜,通過(guò) AssetsLibrary 可以獲取照片和視頻 |
ALAssetsGroup | 通過(guò) ALAssetsGroup 可以獲取某個(gè)相冊(cè)的信息,相冊(cè)下的資源咳榜,同時(shí)也可以對(duì)某個(gè)相冊(cè)添加資源 |
ALAsset | 映射照片庫(kù)中的一個(gè)照片或視頻夏醉,通過(guò) ALAsset 可以獲取某個(gè)照片或視頻的詳細(xì)信息,或者保存照片和視頻 |
ALAssetRepresentation | 對(duì) ALAsset 的封裝(但不是其子類)涌韩,可以更方便地獲取 ALAsset 中的資源信息 |
-
枚舉類型
enum {
ALAssetsGroupLibrary // 本地和 iTunes
ALAssetsGroupAlbum // 從iTunes同步來(lái)的照片畔柔,不包括共享的(例如從各個(gè)軟件中保存下來(lái)的圖片)
ALAssetsGroupEvent // 同步到 iTunes 的(包括相機(jī)導(dǎo)入的)
ALAssetsGroupFaces // 同步 iTunes 的
ALAssetsGroupSavedPhotos // 相機(jī)膠卷
ALAssetsGroupPhotoStream // 照片流
ALAssetsGroupAll // 全部相冊(cè)
};
-
collectionView
/*
* 將相冊(cè)中的圖片放入collectionView數(shù)據(jù)源中
*
* NSEnumerationConcurrent 正序遍歷
* NSEnumerationReverse 反向遍歷
*/
[self.assetsGroup enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result) {
if ([[result valueForProperty:ALAssetPropertyType] isEqual:ALAssetTypePhoto]) {
//只訪問(wèn)照片,不訪問(wèn)視頻
[self.assets addObject:result];
}
} else {
[self.collectionView reloadData];
}
}];