今天給大家講一個乾貨,簡單實用。之前公司的項目需要自定義相冊,並且需要獲取圖片的經緯度信息,使用UIImagePickerController自然是實現不了的。所以就用到了我們今天所說的PhotoKit框架,因爲PhotoKit是iOS8之後出的,所以iOS8以前的項目是不能使用的(可以使用AssetsLibrary,這裏就不多介紹了)。
先來介紹一下PhotoKit的主要屬性:
1.PHPhotoLibrary
官方解釋:PHPhotoLibrary提供對用戶照片庫中的照片、視頻和相關內容的元數據和圖像數據的訪問,包括來自照相機輥、iCloud共享、照片流、從iTunes導入和同步的內容。
簡單的說就是提供了,獲取用戶是否已經開通訪問相冊的權限。
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status == PHAuthorizationStatusAuthorized) {
/// 用戶開通了權限
}else{
/// 用戶沒有開通權限
}
}];
///這裏是PHAuthorizationStatus的所有枚舉參數
typedef NS_ENUM(NSInteger, PHAuthorizationStatus) {
PHAuthorizationStatusNotDetermined = 0, // 用戶尚未作出關於這個應用的選擇。
PHAuthorizationStatusRestricted, // 此應用程序未被授權訪問照片數據。
// 用戶可能無法更改此應用程序的狀態,可能是由於活動限制
// 比如家長控制。
PHAuthorizationStatusDenied, // 用戶已明確拒絕此應用程序訪問照片數據。
PHAuthorizationStatusAuthorized // 用戶已授權此應用程序訪問照片數據。
}
2. PHAssetCollection
繼承於PHCollection,它最主要的功能就是獲取到對應的相冊。通過相冊我們就可以獲取相冊中的圖片了。
這裏是他最常用的方法:
// 通過這個方法以及PHAssetCollectionType和PHAssetCollectionSubtype參數,就能獲取你想要的相冊了。(下面我能翻譯多少就翻譯多少😂)
+ (PHFetchResult<PHAssetCollection *> *)fetchAssetCollectionsWithType:(PHAssetCollectionType)type subtype:(PHAssetCollectionSubtype)subtype options:(nullable PHFetchOptions *)options;
// PHAssetCollectionType的所有參數
typedef NS_ENUM(NSInteger, PHAssetCollectionType) {
PHAssetCollectionTypeAlbum = 1, // 相冊,系統外的
PHAssetCollectionTypeSmartAlbum = 2, // 智能相冊,系統自己分配和歸納的
PHAssetCollectionTypeMoment = 3, // 時刻,系統自動通過時間和地點生成的分組
} PHOTOS_ENUM_AVAILABLE_IOS_TVOS(8_0, 10_0);
typedef NS_ENUM(NSInteger, PHAssetCollectionSubtype) {
// PHAssetCollectionTypeAlbum regular subtypes
PHAssetCollectionSubtypeAlbumRegular = 2, // 在iPhone中自己創建的相冊
PHAssetCollectionSubtypeAlbumSyncedEvent = 3,
PHAssetCollectionSubtypeAlbumSyncedFaces = 4, // 從圖片app中導入的人物照片
PHAssetCollectionSubtypeAlbumSyncedAlbum = 5, // 從圖片app導入的相冊
PHAssetCollectionSubtypeAlbumImported = 6,
// PHAssetCollectionTypeAlbum shared subtypes
PHAssetCollectionSubtypeAlbumMyPhotoStream = 100, // 照片流,照片流和iCloud有關,如果在設置裏關閉了iCloud開關,就獲取不到了
PHAssetCollectionSubtypeAlbumCloudShared = 101, // iCloud的共享相冊,點擊照片上的共享tab創建後就能拿到了,但是前提是你要在設置中打開iCloud的共享開關(打開後才能看見共享tab)
// PHAssetCollectionTypeSmartAlbum subtypes
PHAssetCollectionSubtypeSmartAlbumGeneric = 200,
PHAssetCollectionSubtypeSmartAlbumPanoramas = 201, // 全景圖、全景照片
PHAssetCollectionSubtypeSmartAlbumVideos = 202, // 視頻
PHAssetCollectionSubtypeSmartAlbumFavorites = 203, // 標記爲喜歡、收藏
PHAssetCollectionSubtypeSmartAlbumTimelapses = 204, // 延時拍攝、定時拍攝
PHAssetCollectionSubtypeSmartAlbumAllHidden = 205, // 隱藏的
PHAssetCollectionSubtypeSmartAlbumRecentlyAdded = 206, // 最近添加的、近期添加
PHAssetCollectionSubtypeSmartAlbumBursts = 207, // 連拍
PHAssetCollectionSubtypeSmartAlbumSlomoVideos = 208,
PHAssetCollectionSubtypeSmartAlbumUserLibrary = 209, // 相機膠捲
PHAssetCollectionSubtypeSmartAlbumSelfPortraits PHOTOS_AVAILABLE_IOS_TVOS(9_0, 10_0) = 210, // 使用前置攝像頭拍攝的作品
PHAssetCollectionSubtypeSmartAlbumScreenshots PHOTOS_AVAILABLE_IOS_TVOS(9_0, 10_0) = 211, // 屏幕截圖
PHAssetCollectionSubtypeSmartAlbumDepthEffect PHOTOS_AVAILABLE_IOS_TVOS(10_2, 10_1) = 212,
PHAssetCollectionSubtypeSmartAlbumLivePhotos PHOTOS_AVAILABLE_IOS_TVOS(10_3, 10_2) = 213, // Live Photo資源
PHAssetCollectionSubtypeSmartAlbumAnimated PHOTOS_AVAILABLE_IOS_TVOS(11_0, 11_0) = 214,
PHAssetCollectionSubtypeSmartAlbumLongExposures PHOTOS_AVAILABLE_IOS_TVOS(11_0, 11_0) = 215,
// Used for fetching, if you don't care about the exact subtype
PHAssetCollectionSubtypeAny = NSIntegerMax
} PHOTOS_ENUM_AVAILABLE_IOS_TVOS(8_0, 10_0);
ok,趕快舉個獲取全部相片例子:
// 獲得相機膠捲
PHFetchResult<PHAssetCollection *> *cameraRolls = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil];
// cameraRolls:將來我們就用它來獲取相冊的圖片
不要慌,看這個參數感覺頭大不要緊,一會看到demo的時候,簡單的一批。
3.PHFetchResult
相冊管理的類,是有序的photo實體對象的容器,包含通過給定的檢索條件返回的asset,相冊,一個相冊類型中的所有相冊列表。你要是實在搞不懂我說的是什麼,你就把他想成NSMutableArray。(當然它和NSMutableArray只是用法上類似,他們之間沒什麼關係)
4.PHAsset
重頭戲來了哈,這個就是需要重點介紹的。這個類相當於一張照片的實體,我們可以通過處理變成可見的照片,而且還能獲取到照片的經緯度(前提是有經緯度)、創建時間,這對於產品來說是非常重要的參數。
我們就抽這個類幾個重要的屬性講一下,其他同學們可以自學一下:
/// 像素寬高
@property (nonatomic, assign, readonly) NSUInteger pixelWidth;
@property (nonatomic, assign, readonly) NSUInteger pixelHeight;
/// 創建時間、修改時間
@property (nonatomic, strong, readonly, nullable) NSDate *creationDate;
@property (nonatomic, strong, readonly, nullable) NSDate *modificationDate;
/// 經緯度
@property (nonatomic, strong, readonly, nullable) CLLocation *location;
/// 持續時間
@property (nonatomic, assign, readonly) NSTimeInterval duration;
/// 通過PHAssetCollection獲取PHFetchResult<PHAsset *> *,獲取到PHAsset之後就可以得到圖片了
+ (PHFetchResult<PHAsset *> *)fetchAssetsInAssetCollection:(PHAssetCollection *)assetCollection options:(nullable PHFetchOptions *)options;
哇,看到這些爽不爽啊,獲取個圖片,這麼多相關屬性都出來了。
5. PHImageManager
按照要求獲取制定的圖片
/// 通過PHAsset,加上你需要展示的圖片大小、圖片類型(是否裁剪等)和PHImageRequestOptions去獲取圖片
- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;
/// 這個就是調用的方法獲取圖片
[[PHImageManager defaultManager] requestImageForAsset:self.asset targetSize:CGSizeMake(imageWidth * [UIScreen mainScreen].scale, imageWidth * [UIScreen mainScreen].scale) contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
NSLog(@"獲取的圖片:%@", result);
}];
6.PHImageRequestOptions
請求選項設置,這裏也將它的重點屬性講解一下:
// resize mode. Does not apply when size is PHImageManagerMaximumSize. Defaults to PHImageRequestOptionsResizeModeNone (or no resize)
@property (nonatomic, assign) PHImageRequestOptionsResizeMode resizeMode;
// 自定義設置圖片的大小
typedef NS_ENUM(NSInteger, PHImageRequestOptionsResizeMode) {
PHImageRequestOptionsResizeModeNone = 0, // 保持原size(不調整大小)
PHImageRequestOptionsResizeModeFast, //高效、但不保證圖片的size爲自定義size(由系統去安排,情況不定:有時你設置的size比較小,會根據你設的size,有時又會比大)
PHImageRequestOptionsResizeModeExact, // 嚴格按照自定義size
} PHOTOS_ENUM_AVAILABLE_IOS_TVOS(8_0, 10_0);
// return only a single result, blocking until available (or failure). Defaults to NO
@property (nonatomic, assign, getter=isSynchronous) BOOL synchronous;
// 指定請求是否同步執行。
// specify crop rectangle in unit coordinates of the original image, such as a face. Defaults to CGRectZero (not applicable)
@property (nonatomic, assign) CGRect normalizedCropRect;
// 用於對原始尺寸的圖像進行裁剪,基於比例座標。只在 resizeMode 爲 Exact 時有效。
// delivery mode. Defaults to PHImageRequestOptionsDeliveryModeOpportunistic
@property (nonatomic, assign) PHImageRequestOptionsDeliveryMode deliveryMode;
// 圖像質量。有三種值:Opportunistic,在速度與質量中均衡;HighQualityFormat,不管花費多長時間,提供高質量圖像;FastFormat,以最快速度提供好的質量。 這個屬性只有在 synchronous 爲 true 時有效。
ok,截止到目前,獲取相冊所有重要的類、參數、方法都講完了。我們來講講demo吧。
我覺得整個demo的方法沒有必要一條條的講解,主要是思路和防止一些坑。
1.首先我們在進入控制器的時候,獲取你需要顯示的相冊,再在主控制器顯示第一個相冊。
2.在加載圖片的時候,我建議大家將加載的方法放在cell中完成,但是要保證cell的重用問題,千萬不要把圖片解析到model中,小心撐炸APP。
3.可以做一個單例,用於記錄選中的圖片、選中的總數等等。
其實大家把方法搞明白之後,整個demo的邏輯其實很簡單。
demo的鏈接:傳送門
喜歡的同學點個贊哈😘