iOS 基於PhotoKit框架的自定義相冊

今天給大家講一個乾貨,簡單實用。之前公司的項目需要自定義相冊,並且需要獲取圖片的經緯度信息,使用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的鏈接:傳送門

喜歡的同學點個贊哈😘

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章