照片/视频选择器 - 支持LivePhoto、GIF图片选择、自定义编辑照片/视频、3DTouch预览、浏览网络图片/网络视频 功能 - Imitation weibo photo/image picker - support for LivePhoto, GIF image selection, 3DTouch preview, browse the web image function
APACHE-2.0 License
# Podfile
#
pod 'HXPhotoPickerObjC', '~> 3.3.4'
# SDWebImage
pod 'HXPhotoPickerObjC/SDWebImage', '~> 3.3.4'
# YYWebImage
pod 'HXPhotoPickerObjC/YYWebImage', '~> 3.3.4'
#
pod repo update rm ~/Library/Caches/CocoaPods/search_index.json
HXPhotoPicker
"HXPhotoPicker.h"
//
- (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;
HXCustomAssetModel *assetModel1 = [HXCustomAssetModel assetWithLocaImageName:@"1" selected:YES];
// selected NO
HXCustomAssetModel *assetModel2 = [HXCustomAssetModel assetWithLocaImageName:@"2" selected:NO];
HXCustomAssetModel *assetModel3 = [HXCustomAssetModel assetWithNetworkImageURL:[NSURL URLWithString:@"http://tsnrhapp.oss-cn-hangzhou.aliyuncs.com/1466408576222.jpg"] selected:YES];
// selected NO
HXCustomAssetModel *assetModel4 = [HXCustomAssetModel assetWithNetworkImageURL:[NSURL URLWithString:@"http://tsnrhapp.oss-cn-hangzhou.aliyuncs.com/0034821a-6815-4d64-b0f2-09103d62630d.jpg"] selected:NO];
NSURL *url = [[NSBundle mainBundle] URLForResource:@"QQ_20180301091047" withExtension:@"mp4"];
HXCustomAssetModel *assetModel5 = [HXCustomAssetModel assetWithLocalVideoURL:url selected:YES];
HXPhotoManager *photoManager = [HXPhotoManager managerWithType:HXPhotoManagerSelectedTypePhotoAndVideo];
photoManager.configuration.saveSystemAblum = YES;
photoManager.configuration.photoMaxNum = 0;
photoManager.configuration.videoMaxNum = 0;
photoManager.configuration.maxNum = 10;
photoManager.configuration.selectTogether = YES;
photoManager.configuration.photoCanEdit = NO;
photoManager.configuration.videoCanEdit = NO;
HXWeakSelf
//
photoManager.configuration.previewRespondsToLongPress = ^(UILongPressGestureRecognizer *longPress,
HXPhotoModel *photoModel,
HXPhotoManager *manager,
HXPhotoPreviewViewController *previewViewController) {
hx_showAlert(previewViewController, @"", @"", @"", nil, nil, nil);
};
// view
photoManager.configuration.customPreviewFromView = ^UIView *(NSInteger currentIndex) {
HXPhotoSubViewCell *viewCell = [weakSelf.photoView collectionViewCellWithIndex:currentIndex];
return viewCell;
};
// image
photoManager.configuration.customPreviewFromImage = ^UIImage *(NSInteger currentIndex) {
HXPhotoSubViewCell *viewCell = [weakSelf.photoView collectionViewCellWithIndex:currentIndex];
return viewCell.imageView.image;
};
// view
photoManager.configuration.customPreviewToView = ^UIView *(NSInteger currentIndex) {
HXPhotoSubViewCell *viewCell = [weakSelf.photoView collectionViewCellWithIndex:currentIndex];
return viewCell;
};
[photoManager addCustomAssetModel:@[assetModel1, assetModel2, assetModel3, assetModel4, assetModel5]];
[self hx_presentPreviewPhotoControllerWithManager:photoManager
previewStyle:HXPhotoViewPreViewShowStyleDark
currentIndex:0
photoView:nil];
UIViewController+HXExtension.h
///
/// @param manager
/// @param previewStyle
/// @param currentIndex
/// @param photoView -
- (void)hx_presentPreviewPhotoControllerWithManager:(HXPhotoManager *)manager
previewStyle:(HXPhotoViewPreViewShowStyle)previewStyle
currentIndex:(NSUInteger)currentIndex
photoView:(HXPhotoView * _Nullable)photoView;
//
HXPhotoModel *photoModel = [HXPhotoModel photoModelWithImage:[UIImage imageNamed:@"1"]];
[self hx_presentPhotoEditViewControllerWithManager:self.manager photoModel:photoModel delegate:nil done:^(HXPhotoModel *beforeModel,
HXPhotoModel *afterModel, HXPhotoEditViewController *viewController) {
// beforeModelafterModel
weakSelf.imageView.image = afterModel.thumbPhoto;
} cancel:^(HXPhotoEditViewController *viewController) {
//
}];
//
[self hx_presentWxPhotoEditViewControllerWithConfiguration:self.manager.configuration.photoEditConfigur photoModel:photoModel delegate:nil finish:^(HXPhotoEdit * _Nonnull photoEdit, HXPhotoModel * _Nonnull photoModel, HX_PhotoEditViewController * _Nonnull viewController) {
if (photoEdit) {
//
weakSelf.imageView.image = photoEdit.editPreviewImage;
}else {
//
weakSelf.imageView.image = photoModel.thumbPhoto;
}
//
weakSelf.photoEdit = photoEdit;
} cancel:^(HX_PhotoEditViewController * _Nonnull viewController) {
//
}];
//
NSURL *url = [[NSBundle mainBundle] URLForResource:@"QQ_20180301091047" withExtension:@"mp4"];
HXPhotoModel *videoModel = [HXPhotoModel photoModelWithVideoURL:url];
[self hx_presentVideoEditViewControllerWithManager:self.manager videoModel:videoModel delegate:nil done:^(HXPhotoModel *beforeModel,
HXPhotoModel *afterModel, HXVideoEditViewController *viewController) {
// beforeModelafterModel
weakSelf.imageView.image = afterModel.thumbPhoto;
} cancel:^(HXVideoEditViewController *viewController) {
//
}];
// _manager.configuration.requestImageAfterFinishingSelection YES
//
//
// exportVideoURLForHighestQuality YES
//
//
for (HXPhotoModel *model in self.selectList) {
//
//
if (model.subType == HXPhotoModelMediaSubTypePhoto) {
//
if (model.photoEdit) {
//
//
model.photoEdit.editPreviewImage;
return;
}
//
if (model.type == HXPhotoModelMediaTypeCameraPhoto) {
//
// < ios9.0PHAsset
// >= ios9.0 PHAsset
// model.asset PHAsset
//
if (model.cameraPhotoType == HXPhotoModelMediaTypeCameraPhotoTypeLocal) {
//
}else if (model.cameraPhotoType == HXPhotoModelMediaTypeCameraPhotoTypeLocalGif) {
// gif
}else if (model.cameraPhotoType == HXPhotoModelMediaTypeCameraPhotoTypeNetWork) {
//
}else if (model.cameraPhotoType == HXPhotoModelMediaTypeCameraPhotoTypeNetWorkGif) {
// gif
}
//
if (model.networkPhotoUrl) {
//
//
}else {
//
// model.previewPhoto model.thumbPhotoimage
}
}else {
// model.asset PHAsset
// Gif LivePhoto
if (model.type == HXPhotoModelMediaTypePhoto) {
// livePhotoGIFLivePhoto
// NSDataURL
// GIF model.photoFormat == HXPhotoModelFormatGIF
// requestImageAfterFinishingSelection = YES model.previewPhoto model.thumbPhoto
// image
// size PHImageManagerMaximumSizesize
CGSize size;
if (self.original) {
size = PHImageManagerMaximumSize;
}else {
size = CGSizeMake(model.imageSize.width * 0.5, model.imageSize.height * 0.5);
}
[model requestPreviewImageWithSize:size startRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel * _Nullable model) {
// iCloud
} progressHandler:^(double progress, HXPhotoModel * _Nullable model) {
// iCloud
} success:^(UIImage * _Nullable image, HXPhotoModel * _Nullable model, NSDictionary * _Nullable info) {
// image
} failed:^(NSDictionary * _Nullable info, HXPhotoModel * _Nullable model) {
//
}];
}else if (model.type == HXPhotoModelMediaTypePhotoGif) {
// requestImageAfterFinishingSelection = YES model.imageURL
model.imageURL;
// imageurldata
// url
[model requestImageURLStartRequestICloud:nil progressHandler:nil success:^(NSURL * _Nullable imageURL, HXPhotoModel * _Nullable model, NSDictionary * _Nullable info) {
// imageURL
} failed:nil];
// data
[model requestImageDataStartRequestICloud:nil progressHandler:nil success:^(NSData * _Nullable imageData, UIImageOrientation orientation, HXPhotoModel * _Nullable model, NSDictionary * _Nullable info) {
// imageData
} failed:nil];
}else if (model.type == HXPhotoModelMediaTypeLivePhoto) {
// LivePhotorequestImageAfterFinishingSelection = YES livephoto
// livephotolivephoto
// livephoto
[model requestLivePhotoAssetsWithSuccess:^(NSURL * _Nullable imageURL, NSURL * _Nullable videoURL, BOOL isNetwork, HXPhotoModel * _Nullable model) {
// imageURL - LivePhoto
// videoURL - LivePhoto
} failed:^(NSDictionary * _Nullable info, HXPhotoModel * _Nullable model) {
//
}];
}
// model.asset PHAsset
PHAsset *asset = model.asset;
//
}
}else if (model.subType == HXPhotoModelMediaSubTypeVideo) {
//
if (model.type == HXPhotoModelMediaTypeVideo) {
//
// requestImageAfterFinishingSelection = YES model.videoURL
model.videoURL;
// AVAsset AVAssetExportSession
// AVAsset
[model requestAVAssetStartRequestICloud:nil progressHandler:nil success:^(AVAsset * _Nullable avAsset, AVAudioMix * _Nullable audioMix, HXPhotoModel * _Nullable model, NSDictionary * _Nullable info) {
// avAsset
// avAsset
} failed:nil];
// AVAssetExportSession
[model requestAVAssetExportSessionStartRequestICloud:nil progressHandler:nil success:^(AVAssetExportSession * _Nullable assetExportSession, HXPhotoModel * _Nullable model, NSDictionary * _Nullable info) {
} failed:nil];
// HXPhotoModel
// presetName
[model exportVideoWithPresetName:AVAssetExportPresetMediumQuality startRequestICloud:nil iCloudProgressHandler:nil exportProgressHandler:^(float progress, HXPhotoModel * _Nullable model) {
// iCloud
} success:^(NSURL * _Nullable videoURL, HXPhotoModel * _Nullable model) {
// , videoURL
} failed:nil];
// model.asset PHAsset
PHAsset *asset = model.asset;
//
}else {
//
if (model.cameraVideoType == HXPhotoModelMediaTypeCameraVideoTypeLocal) {
//
// model.videoURL
}else if (model.cameraVideoType == HXPhotoModelMediaTypeCameraVideoTypeNetWork) {
//
// model.videoURL
// model.networkPhotoUrl
}
}
}
}
HXPhotoModel
/// HXPhotoModel
/// @param photoModel
- (BOOL)isEqualToPhotoModel:(HXPhotoModel * _Nullable)photoModel;
//
- (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
///
- (NSArray<HXPhotoModel *> *)getLocalModelsInFile;
///
- (BOOL)saveLocalModelsToFile;
///
- (BOOL)deleteLocalModelsInFile;
/// manager
/// @param models
- (void)addLocalModels:(NSArray<HXPhotoModel *> *)models;
/// manager
- (void)addLocalModels;
HXPhotoManagerHXCustomAssetModel
/**
@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;
///
/// @param videoURL
/// @param videoCoverURL
/// @param videoDuration
/// @param selected
+ (instancetype)assetWithNetworkVideoURL:(NSURL *)videoURL videoCoverURL:(NSURL *)videoCoverURL videoDuration:(NSTimeInterval)videoDuration selected:(BOOL)selected;
HXCustomAssetModelHXPhotoManager
/**
/ ,
/
.
.
type = HXPhotoManagerSelectedTypePhoto
type = HXPhotoManagerSelectedTypeVideo
@param assetArray
*/
- (void)addCustomAssetModel:(NSArray<HXCustomAssetModel *> *)assetArray;
//
[self.manager addCustomAssetModel:@[assetModel1, assetModel2, assetModel3, assetModel4, assetModel5, assetModel6]];
// HXPhotoView
[self.photoView refreshView];
1SDWebImage
2YYWebImage
https://github.com/ibireme/YYKit/issues/573
https://www.jianshu.com/p/9c117dbe22a8
SDWebImage
YYKit
HXPhotoConfiguration.h
HXPhotoLanguageTypeSys = 0, //
HXPhotoLanguageTypeSc, //
HXPhotoLanguageTypeTc, //
HXPhotoLanguageTypeJa, //
HXPhotoLanguageTypeKo, //
HXPhotoLanguageTypeEn //
/**
*/
@property (assign, nonatomic) HXPhotoLanguageType languageType;
HXPhotoModeltype
HXPhotoModelMediaTypePhoto = 0, //!<
HXPhotoModelMediaTypeLivePhoto = 1, //!< LivePhoto
HXPhotoModelMediaTypePhotoGif = 2, //!< gif
HXPhotoModelMediaTypeCameraPhoto = 5, //!< /
typeHXPhotoModelMediaTypeCameraPhotonetworkPhotoUrl
thumbPhoto/previewPhoto
thumbPhoto/previewPhoto
HXPhotoModelimageimageData
1.HXPhotoModelPHAssetAVAssetAVAssetExportSessionAVAsset
2.PHAssetHXPhotoModelVideoURL
HXPhotoModel
/
9.0/PHAsset
HXPhotoModelPHAssettype HXPhotoModelMediaTypePhoto / HXPhotoModelMediaTypeVideo
/
HXPhotoModelPHAssettype HXPhotoModelMediaTypeCameraPhoto / HXPhotoModelMediaTypeCameraVideo
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 {
NSData *imageData = [NSData dataWithContentsOfFile:path];
UIImage *image = [UIImage imageWithData:imageData];
}
} 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) {
// iCloudimageData
} 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) {
//
}];
HXPhotoView
- (void)photoView:(HXPhotoView *)photoView updateFrame:(CGRect)frame
frame.size.height HXPhotoView
demo11
- v3.3.4-ObjC
- v3.3.2-iOS16iPhone14Pro/ProMaxiOS9.3.5 fileSize
- v3.3.1-``cell,
- v3.3.0-HXPhotoModel
- v3.2.9-iOS15
- v3.2.7-iOS15
- v3.2.6-""iPhone se 12.2
- v3.2.5-iOS15
- v3.2.4-
- v3.2.3-iOS 14
- v3.2.2-podHXPhotoViewitemSize pod 'HXPhotoPickerObjC/CustomItem'
- v3.2.1-gifURL
- v3.2.0-
- v3.1.9-
- v3.1.8-
- v3.1.7-HXPhotoModel
- v3.1.6-requestImageAfterFinishingSelectionYES
- v3.1.5-
- v3.1.4-fix previewPhotonil
- v3.1.3-darkiOS14iCloud/PHAsset
- v3.1.2-iPhone12PHAssetCollectionPHAsset
- v3.1.1-darkiOS14
- v3.1.0-iOS14iOS11
- v3.0.8-
- v3.0.7-/
- v3.0.6-...
- v3.0.5-LivePhotoLivePhoto
- v3.0.4-
- v3.0.3-podxibgif
- v3.0.2-ios14titleView
- v3.0.0-
...
- v2.4.5-pod SDWebImage/YYWebImage
- v2.4.4-bugHXPhotoView...Demo15
- v2.4.3-Demo14HXPhotoViewItem
- v2.4.2-
- v2.4.1-/podAFNetworking
- v2.4.0-demo8/
- v2.3.8-HXPhotoViewMasonryDemoXibMasonry
- v2.3.7-/
- v2.3.6-HXPhotoModelfileURL
- v2.3.5-requestImageAfterFinishingSelection YESHXPhotoViewActionSheetviewios13...
- v2.3.4-ios13requestImageAfterFinishingSelectionblock
- v2.3.3-podyy
- v2.3.2-ios13
- v2.3.1-podsdyy
- v2.3.0-SDWebImage v5.0.0
- v2.2.9-UI
- v2.2.7-NSArray+HXExtension
- v2.2.6-ipadios8Demo
- v2.2.5-
- 2019-1-18 iCloudcellDateDate
- 2019-1-12 HEIC
- 2019-1-9
- 2019-1-7 ios9PHAsset
- v2.2.3-Demo9 cell3DTouchDemo13 /
- v2.2.2-iphone XS - XSMax - XRYYWebImageYYWebImageSDYYYY
- v2.2.1-HXPhotoView
- v2.2.0-xibDemo11//Demo12
- v2.1.9-Demo2
- v2.1.8-
- v2.1.7-
- v2.1.5-cell
- v2.1.4-
- 2017-11-21iCloud
- v2.1.2-
- 2017-11-14
- 2017-11-06
- v2.1.1-(,)
- v2.1.0-ios11iphone X / 3DTouchgif / iCloud
- v2.0.9-tempdemo
- v2.0.8-
- v2.0.7-
- v2.0.6-ios8
- v2.0.5-
- ...
- 2017-08-12HXPhotoTools
- 2017-08-1064
- 2017-08-08/
- 2017-07-26cell3DTouch/Demo
- 2017-07-05,
- 2017-07-01
- 2017-06-26
- ...
- 2017-03-0790
- 2017-03-06