一個好用的照片選擇器
github地址:https://github.com/SilenceLove/HXPhotoPicker
照片選擇器 支持 ios8 以上
IMG_4311.PNG
IMG_4308.PNG
IMG_4309.PNG
目錄
特性 - Features
- √ 查看/選擇GIF圖片
- √ 照片、視頻可同時多選/原圖
- √ 3DTouch預覽照片
- √ 長按拖動改變順序
- √ 自定義相機拍照/錄制視頻
- √ 自定義轉場動畫
- √ 查看/選擇LivePhoto IOS9.1以上才有用
- √ 支持瀏覽網絡圖片
- √ 支持自定義裁剪圖片
- √ 觀察系統相冊變化實時增刪
- √ 支持傳入本地圖片
- √ 支持在線下載iCloud上的資源
- √ 兩種相冊展現方式(列表、彈窗)
- √ 支持Cell上添加
- √ 同一界面多個不同選擇器
安裝 - Installation
- Cocoapods:
pod 'HXPhotoPicker', '~> 2.2.5'
搜索不到庫或最新版請執行pod repo update
- 手動導入:將項目中的“HXPhotoPicker”文件夾拖入項目中
- 網絡圖片加載使用的是SDWebImage v4.4.1 || YYWebImage v1.0.5
- 如果想要加載網絡gif圖片請使用YYWebImage
- 使用前導入頭文件 "HXPhotoPicker.h"
要求 - Requirements
- iOS8及以上系統可使用. ARC環境. - iOS 8 or later. Requires ARC
- 在Xcode8環境下將項目運行在iOS10的設備/模擬器中,訪問相冊和相機需要配置三個info.plist文件
- Privacy - Photo Library Usage Description 和 Privacy - Camera Usage Description 以及 Privacy - Microphone Usage Description
- 相機拍照功能請使用真機調試
示例 - Examples
如何獲取照片和視頻
根據選擇完成后返回的 HXPhotoModel 對象獲取
// 獲取 image
// 如果為網絡圖片的話會先下載
// size 代表獲取image的質量
// PHImageManagerMaximumSize 獲取原圖
[photoModel requestPreviewImageWithSize:PHImageManagerMaximumSize startRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel *model) {
// 如果照片在iCloud上會去下載,此回調代表開始下載iCloud上的照片
// 如果照片在本地存在此回調則不會走
} progressHandler:^(double progress, HXPhotoModel *model) {
// iCloud下載進度
// 如果為網絡圖片,則是網絡圖片的下載進度
} success:^(UIImage *image, HXPhotoModel *model, NSDictionary *info) {
// 獲取成功
} failed:^(NSDictionary *info, HXPhotoModel *model) {
// 獲取失敗
}];
// 獲取 imageData
// 如果為網絡圖片的話會先下載
[photoModel requestImageDataStartRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel *model) {
// 開始下載iCloud上照片的imageData
} progressHandler:^(double progress, HXPhotoModel *model) {
// iCloud下載進度
} success:^(NSData *imageData, UIImageOrientation orientation, HXPhotoModel *model, NSDictionary *info) {
// 獲取成功
} failed:^(NSDictionary *info, HXPhotoModel *model) {
// 獲取失敗
}];
// 獲取視頻的 AVAsset
[photoModel requestAVAssetStartRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel *model) {
// 開始下載iCloud上的視頻
} progressHandler:^(double progress, HXPhotoModel *model) {
// iCloud下載進度
} success:^(AVAsset *avAsset, AVAudioMix *audioMix, HXPhotoModel *model, NSDictionary *info) {
// 獲取成功
} failed:^(NSDictionary *info, HXPhotoModel *model) {
// 獲取失敗
}];
// 獲取 LivePhoto
// PHImageManagerMaximumSize代表原圖
[photoModel requestLivePhotoWithSize:PHImageManagerMaximumSize startRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel *model) {
// 開始下載iCloud上的 LivePhoto
} progressHandler:^(double progress, HXPhotoModel *model) {
// iCloud下載進度
} success:^(PHLivePhoto *livePhoto, HXPhotoModel *model, NSDictionary *info) {
// 獲取成功
} failed:^(NSDictionary *info, HXPhotoModel *model) {
// 獲取失敗
}];
// 導出視頻地址
// presetName 視頻導出的質量
[photoModel exportVideoWithPresetName:AVAssetExportPresetHighestQuality startRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel *model) {
// 開始下載iCloud上的視頻
} iCloudProgressHandler:^(double progress, HXPhotoModel *model) {
// iCloud下載進度
} exportProgressHandler:^(float progress, HXPhotoModel *model) {
// 視頻導出進度
} success:^(NSURL *videoURL, HXPhotoModel *model) {
// 導出成功
} failed:^(NSDictionary *info, HXPhotoModel *model) {
// 導出失敗
}];
NSArray+HXExtension
/**
獲取image
如果model是視頻的話,獲取的則是視頻封面
@param original 是否原圖
@param completion imageArray 獲取成功的image數組, errorArray 獲取失敗的model數組
*/
- (void)hx_requestImageWithOriginal:(BOOL)original completion:(void (^)(NSArray<UIImage *> * _Nullable imageArray, NSArray<HXPhotoModel *> * _Nullable errorArray))completion;
/**
獲取imageData
@param completion 完成回調,獲取失敗的不會添加到數組中
*/
- (void)hx_requestImageDataWithCompletion:(void (^)(NSArray<NSData *> * _Nullable imageDataArray))completion;
/**
獲取AVAsset
@param completion 完成回調,獲取失敗的不會添加到數組中
*/
- (void)hx_requestAVAssetWithCompletion:(void (^)(NSArray<AVAsset *> * _Nullable assetArray))completion;
/**
獲取視頻地址
@param presetName AVAssetExportPresetHighestQuality / AVAssetExportPresetMediumQuality
@param completion 完成回調,獲取失敗的不會添加到數組中
*/
- (void)hx_requestVideoURLWithPresetName:(NSString *)presetName completion:(void (^)(NSArray<NSURL *> * _Nullable videoURLArray))completion;
跳轉相冊選擇照片
// 懶加載 照片管理類
- (HXPhotoManager *)manager {
if (!_manager) {
_manager = [[HXPhotoManager alloc] initWithType:HXPhotoManagerSelectedTypePhotoAndVideo];
}
return _manager;
}
// 一個方法調用
HXWeakSelf
[self hx_presentSelectPhotoControllerWithManager:self.manager didDone:^(NSArray<HXPhotoModel *> *allList, NSArray<HXPhotoModel *> *photoList, NSArray<HXPhotoModel *> *videoList, BOOL isOriginal, UIViewController *viewController, HXPhotoManager *manager) {
weakSelf.total.text = [NSString stringWithFormat:@"總數量:%ld ( 照片:%ld 視頻:%ld )",allList.count, photoList.count, videoList.count];
weakSelf.original.text = isOriginal ? @"YES" : @"NO";
NSSLog(@"block - all - %@",allList);
NSSLog(@"block - photo - %@",photoList);
NSSLog(@"block - video - %@",videoList);
} cancel:^(UIViewController *viewController, HXPhotoManager *manager) {
NSSLog(@"block - 取消了");
}];
// 照片選擇控制器
HXCustomNavigationController *nav = [[HXCustomNavigationController alloc] initWithManager:self.manager delegate:self];
[self presentViewController:nav animated:YES completion:nil];
// 通過 HXCustomNavigationControllerDelegate 代理返回選擇的圖片以及視頻
/**
點擊完成按鈕
@param photoNavigationViewController self
@param allList 已選的所有列表(包含照片、視頻)
@param photoList 已選的照片列表
@param videoList 已選的視頻列表
@param original 是否原圖
*/
- (void)photoNavigationViewController:(HXCustomNavigationController *)photoNavigationViewController didDoneAllList:(NSArray<HXPhotoModel *> *)allList photos:(NSArray<HXPhotoModel *> *)photoList videos:(NSArray<HXPhotoModel *> *)videoList original:(BOOL)original;
/**
點擊取消
@param photoNavigationViewController self
*/
- (void)photoNavigationViewControllerDidCancel:(HXCustomNavigationController *)photoNavigationViewController;
使用HXPhotoView布局
// 懶加載 照片管理類
- (HXPhotoManager *)manager {
if (!_manager) {
_manager = [[HXPhotoManager alloc] initWithType:HXPhotoManagerSelectedTypePhotoAndVideo];
}
return _manager;
}
HXPhotoView *photoView = [[HXPhotoView alloc] initWithFrame:CGRectMake((414 - 375) / 2, 100, 375, 400) manager:self.manager];
photoView.delegate = self;
photoView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:photoView];
// 代理返回 選擇、移動順序、刪除之后的圖片以及視頻
- (void)photoView:(HXPhotoView *)photoView changeComplete:(NSArray<HXPhotoModel *> *)allList photos:(NSArray<HXPhotoModel *> *)photos videos:(NSArray<HXPhotoModel *> *)videos original:(BOOL)isOriginal;
// 當view更新高度時調用
- (void)photoView:(HXPhotoView *)photoView updateFrame:(CGRect)frame;
// 刪除網絡圖片的地址
- (void)photoView:(HXPhotoView *)photoView deleteNetworkPhoto:(NSString *)networkPhotoUrl;
具體請查看HXPhotoView.h
...
如何保存草稿
通過 HXPhotoManager 對象進行存儲
/**
保存模型數組到本地
@param success 成功
@param failed 失敗
*/
- (void)saveSelectModelArraySuccess:(void (^)(void))success failed:(void (^)(void))failed;
/**
刪除本地保存的模型數組
@return success or failed
*/
- (BOOL)deleteLocalSelectModelArray;
/**
獲取保存在本地的模型數組
*/
- (void)getSelectedModelArrayComplete:(void (^)(NSArray<HXPhotoModel *> *modelArray))complete;
// 保存草稿
[self.manager saveSelectModelArraySuccess:^{
// 保存草稿成功
} failed:^{
// 保存草稿失敗
}];
// 獲取草稿
[self.manager getSelectedModelArrayComplete:^(NSArray<HXPhotoModel *> *modelArray) {
if (modelArray.count) {
// 獲取到保存的草稿給manager
[weakSelf.manager addModelArray:modelArray];
// 刷新HXPhotoView
[weakSelf.photoView refreshView];
}
}];
如何添加網絡/本地圖片、視頻
通過 HXPhotoManager、HXCustomAssetModel 進行添加
/**
根據本地圖片名初始化
@param imageName 本地圖片名
@param selected 是否選中
@return HXCustomAssetModel
*/
+ (instancetype)assetWithLocaImageName:(NSString *)imageName selected:(BOOL)selected;
/**
根據本地UIImage初始化
@param image 本地圖片
@param selected 是否選中
@return HXCustomAssetModel
*/
+ (instancetype)assetWithLocalImage:(UIImage *)image selected:(BOOL)selected;
/**
根據網絡圖片地址初始化
@param imageURL 網絡圖片地址
@param thumbURL 網絡圖片縮略圖地址
@param selected 是否選中
@return HXCustomAssetModel
*/
+ (instancetype)assetWithNetworkImageURL:(NSURL *)imageURL networkThumbURL:(NSURL *)thumbURL selected:(BOOL)selected;
/**
根據本地視頻地址初始化
@param videoURL 本地視頻地址
@param selected 是否選中
@return HXCustomAssetModel
*/
+ (instancetype)assetWithLocalVideoURL:(NSURL *)videoURL selected:(BOOL)selected;
創建HXCustomAssetModel完成后,通過HXPhotoManager對象的這個方法進行添加
/**
添加自定義資源模型
如果圖片/視頻 選中的數量超過最大選擇數時,之后選中的會變為未選中
如果設置的圖片/視頻不能同時選擇時
圖片在視頻前面的話只會將圖片添加到已選數組.
視頻在圖片前面的話只會將視頻添加到已選數組.
如果 type = HXPhotoManagerSelectedTypePhoto 時 會過濾掉視頻
如果 type = HXPhotoManagerSelectedTypeVideo 時 會過濾掉圖片
@param assetArray 模型數組
*/
- (void)addCustomAssetModel:(NSArray<HXCustomAssetModel *> *)assetArray;
// 添加
[self.manager addCustomAssetModel:@[assetModel1, assetModel2, assetModel3, assetModel4, assetModel5, assetModel6]];
// 完成后刷新HXPhotoView
[self.photoView refreshView];
相關問題
1. pod YYWebImage與YYKit沖突
解決方案:將YYKit拆開分別導入
2. 如何更換語言
HXPhotoConfiguration.h
設置語言類型
HXPhotoLanguageTypeSys = 0, // 跟隨系統語言
HXPhotoLanguageTypeSc, // 中文簡體
HXPhotoLanguageTypeTc, // 中文繁體
HXPhotoLanguageTypeJa, // 日文
HXPhotoLanguageTypeKo, // 韓文
HXPhotoLanguageTypeEn // 英文
/**
語言類型
默認 跟隨系統
*/
@property (assign, nonatomic) HXPhotoLanguageType languageType;
3. 選擇完照片后其他界面視圖往下偏移
方法一:
/**
如果選擇完照片返回之后,
原有界面繼承UIScrollView的視圖都往下偏移一個導航欄距離的話,
那么請將這個屬性設置為YES,即可恢復。
*/
@Property (assign, nonatomic) BOOL restoreNavigationBar;
方法二:
在選擇完照片之后加上
[UINavigationBar appearance].translucent = NO;
4. 關于圖片
根據HXPhotoModel的type屬性來區分圖片類型
HXPhotoModelMediaTypePhoto = 0, //!< 相冊里的普通照片
HXPhotoModelMediaTypeLivePhoto = 1, //!< LivePhoto
HXPhotoModelMediaTypePhotoGif = 2, //!< gif圖
HXPhotoModelMediaTypeCameraPhoto = 5, //!< 通過相機拍的臨時照片、本地/網絡圖片
當type為HXPhotoModelMediaTypeCameraPhoto時,如果networkPhotoUrl不為空的話,那么這張圖片就是網絡圖片
如果為本地圖片時thumbPhoto/previewPhoto就是本地圖片
不為本地圖片時thumbPhoto/previewPhoto的值都是臨時存的只用于展示
HXPhotoModel已提供方法獲取image或者imageData
5. 關于視頻的URL
1.如果選擇的HXPhotoModel的PHAsset有值,需要先獲取AVAsset,再使用AVAssetExportSession根據AVAsset導出視頻地址
2.如果PHAsset為空的話,則代表此視頻是本地視頻??梢灾苯親XPhotoModel里的VideoURL屬性
HXPhotoModel已提供方法獲取
6. 關于相機拍照
當拍攝的照片/視頻保存到系統相冊
如果系統版本為9.0及以上時,拍照后的照片/視頻保存相冊后會獲取保存后的PHAsset,保存的時候如果有定位信息也會把定位信息保存到相冊
HXPhotoModel里PHAsset有值并且type為 HXPhotoModelMediaTypePhoto / HXPhotoModelMediaTypeVideo
以下版本的和不保存相冊的都只是存在本地的臨時圖片/視頻
HXPhotoModel里PHAsset為空并且type為 HXPhotoModelMediaTypeCameraPhoto / HXPhotoModelMediaTypeCameraVideo
7. 關于原圖
根據代理或者block回調里的 isOriginal 來判斷是否選擇了原圖
方法一:
// 獲取原圖
// 本地圖片、網絡圖片調用此方法會直接進入失敗回調
// 本地圖片獲取原圖 model.thumbPhoto / model.previewPhoto
// 網絡圖片獲取原圖 如果 model.thumbPhoto / model.previewPhoto 都為空的話,說明還沒有下載完成或者下載失敗了,重新下載即可。也可以直接用網絡圖片地址 model.networkPhotoUrl 下載 或者調用requestPreviewImageWithSize:progressHandler:success:failed
// 這個方法只針對有photoModel.asset不為空的情況
[photoModel requestImageURLStartRequestICloud:^(PHContentEditingInputRequestID iCloudRequestId, HXPhotoModel *model) {
// 如果照片在iCloud上會去下載,此回調代表開始下載iCloud上的照片
// 如果照片在本地存在此回調則不會走
} progressHandler:^(double progress, HXPhotoModel *model) {
// iCloud下載進度
} success:^(NSURL *imageURL, HXPhotoModel *model, NSDictionary *info) {
// 獲取成功
// imageURL圖片地址
if ([imageURL.relativePath.pathExtension isEqualToString:@"HEIC"]) {
// 處理一下 HEIC 格式圖片
CIImage *ciImage = [CIImage imageWithContentsOfURL:imageURL];
CIContext *context = [CIContext context];
NSString *key = (__bridge NSString *)kCGImageDestinationLossyCompressionQuality;
NSData *jpgData = [context JPEGRepresentationOfImage:ciImage colorSpace:ciImage.colorSpace options:@{key : @1}];
UIImage *image = [UIImage imageWithData:jpgData];
}else {
UIImage *image = [UIImage imageWithContentsOfFile:path];
}
} failed:^(NSDictionary *info, HXPhotoModel *model) {
// 獲取失敗
}];
// 根據 size 獲取高清圖或者縮略圖 , size只針對 PHAsset 有值的情況下有效
// 如果 size (width <= 0, height <= 0) / PHImageManagerMaximumSize 則會獲取原圖
// 本地圖片直接返回本地圖片的image
// 網絡圖片直接返回網絡圖片下載完成后的image
[photoModel requestPreviewImageWithSize:size startRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel *model) {
// 如果照片在iCloud上會去下載,此回調代表開始下載iCloud上的照片
// 如果照片在本地存在此回調則不會走
} progressHandler:^(double progress, HXPhotoModel *model) {
// iCloud下載進度
// 如果為網絡圖片,則是網絡圖片的下載進度
} success:^(UIImage *image, HXPhotoModel *model, NSDictionary *info) {
// 獲取成功
} failed:^(NSDictionary *info, HXPhotoModel *model) {
// 獲取失敗
}];
方法二:
// 獲取 imageData 根據data來處理
// 如果為網絡圖片的話會先下載
[photoModel requestImageDataStartRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel *model) {
// 開始下載iCloud上照片的imageData
} progressHandler:^(double progress, HXPhotoModel *model) {
// iCloud下載進度
} success:^(NSData *imageData, UIImageOrientation orientation, HXPhotoModel *model, NSDictionary *info) {
// 獲取成功
if ([HXPhotoTools assetIsHEIF:model.asset]) {
// 處理一下 HEIC 格式圖片
CIImage *ciImage = [CIImage imageWithData:imageData];
CIContext *context = [CIContext context];
NSData *jpgData = [context JPEGRepresentationOfImage:ciImage colorSpace:ciImage.colorSpace options:@{}];
// jpgData 轉換后的imageData
}
} failed:^(NSDictionary *info, HXPhotoModel *model) {
// 獲取失敗
}];