#前言 最近做的项目中遇到了自定义相册这个需求,于是就搜索到了Photos这个框架,说来惭愧。。这个是iOS8的东西,现在才用到。。由于网上的各种讲解也很多,我就只讲讲里面的遇到的坑和用法,当做笔记记录一下吧
先来看一下效果图
大概就是这样的,点击按钮获取系统相册资源,然后放到自定义的界面中,我们的项目底部需要加入预览的scroll,然后就是大图查看,图片回调。。具体的代码里面有详细注释。。
#好了,简单粗暴,直接上关键代码 ##获取相册权限
//相册权限判断
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusDenied)
{
//相册权限未开启
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
// app名称
NSString *app_Name = [infoDictionary objectForKey:@"CFBundleDisplayName"];
[weakSelf SetAlertWithTitle:@"提醒" andMessage:[NSString stringWithFormat:@"请在iPhone的“设置->隐私->照片”开启%@访问你的手机相册",app_Name]];
}
else if(status == PHAuthorizationStatusNotDetermined)
{
//相册进行授权
/* * * 第一次安装应用时直接进行这个判断进行授权 * * */
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status)
{
//授权后直接打开照片库
if (status == PHAuthorizationStatusAuthorized)
{
dispatch_async(dispatch_get_main_queue(), ^
{
[weakSelf pushViewController];
});
}
}];
}
else if (status == PHAuthorizationStatusAuthorized)
{
[weakSelf pushViewController];
}
复制代码
##然后就是获取系统相册资源了
-(void) getSystemPhotos
{
// 获取所有资源的集合,并按资源的创建时间排序
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
dispatch_async(dispatch_get_global_queue(0,0), ^{
// 获得相机胶卷的图片
PHFetchResult<PHAssetCollection *> *collectionResult1 = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
for (PHAssetCollection *collection in collectionResult1) {
if (![collection.localizedTitle isEqualToString:@"Camera Roll"]) continue;
[self searchAllImagesInCollection:collection];
break;
}
});
}
- (void)searchAllImagesInCollection:(PHAssetCollection *)collection
{
// 采取同步获取图片(只获得一次图片)
PHImageRequestOptions *imageOptions = [[PHImageRequestOptions alloc] init];
imageOptions.resizeMode = PHImageRequestOptionsResizeModeFast;
imageOptions.synchronous = YES;
imageOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
PHVideoRequestOptions *videoOptions = [[PHVideoRequestOptions alloc] init];
videoOptions.deliveryMode = PHVideoRequestOptionsDeliveryModeFastFormat;
__weak typeof (self) weakSelf = self;
// 遍历这个相册中的所有资源
PHFetchResult<PHAsset *> *assetResult = [PHAsset fetchAssetsInAssetCollection:collection options:nil];
for (PHAsset *asset in assetResult) {
if (weakSelf.isPhotoModel) {
// 过滤非图片
if (asset.mediaType != PHAssetMediaTypeImage) continue;
PhotoModel *photo = [[PhotoModel alloc] init];
photo.asset = asset;
[_imgViewArr addObject:photo];
}
else
{
// 过滤非视频
if (asset.mediaType != PHAssetMediaTypeVideo) continue;
PhotoModel *photo = [[PhotoModel alloc] init];
photo.asset = asset;
[_imgViewArr addObject:photo];
}
}
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf loadMainView];
});
}
复制代码
这里有一个重点,就是获取到的asset资源一定不要尝试在这里使用requestImageForAsset方法去获得图片信息,特别是高清图,一到真机上几百张图片加载内存暴增导致闪退,就算使用裁剪图片或者PHImageRequestOptionsResizeModeFast模式,也会有一小段的空白时间,并不能进来后瞬间显示图片,所以此处我选择直接将asset保存进数组中,利用collctionview的重用机制,在自定义的cell里面再去使用requestImageForAsset加载,效果会好很多,自定义CollectionViewCell中的代码如下
-(void)loadPhotoData:(PhotoModel *)photo withTargetSize:(CGSize)target state:(BOOL)isPhotoModel
{
__weak typeof (self) weakSelf = self;
if (photo)
{
[[PHImageManager defaultManager] requestImageForAsset:photo.asset targetSize:CGSizeMake(200, 200) contentMode:PHImageContentModeAspectFit options:nil resultHandler:^(UIImage *result, NSDictionary *info){
//修正图片方向
UIImage *targetImg = [weakSelf fixOrientation:result];
//缩小图片
targetImg = [weakSelf reSizeImage:targetImg ForSize:target];
weakSelf.PhotoImg.image = targetImg;
photo.isPhotoModel = YES;
}];
if (!isPhotoModel) {
_bottom.hidden = NO;
PHImageManager *manager = [PHImageManager defaultManager];
[manager requestAVAssetForVideo:photo.asset options:nil resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info)
{
//CMTime转换
NSTimeInterval total = CMTimeGetSeconds(asset.duration);
NSString *duration = [weakSelf stringWithTime:total];
//回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.VideoDuration.text = duration;
photo.asset_video = asset;
photo.isPhotoModel = NO;
});
}];
}
}
}
复制代码
这段代码中还加入了是否为图片模式的判断,如果是选择的视频,则这个cell中就将视频asset保存到对应的key中,之后再通过AVPlayer去播放这个资源
#结尾 首先感谢网上各位大神的资料讲解,我也看过好几份例子。。GitHub上那几个其实都有一点小问题(图片回调不全什么的,希望大神看到不要见怪)。。不能满足我们项目的需求,所以就自己撸了一个。。
目前我在使用Photos时遇到最大的一个坑就是上文中提到的内存暴增导致的闪退问题,一直尝试着在外部获取高清图片再保存进数组,后来无意间发现利用collctionview的重用就解决了这个问题,GIF中的图片回调什么的我就不一一列举了,代码里面我几乎都注释了,需要的可以去看看,觉得有用的话记得给个star吧~
PS:对了,我摄像头拍照录视频的功能还没加进来,如果有需要,时间充裕的话,我会尽量补上~
地址:GitHub
#更新 现已加入摄像头拍照录像功能、加入iOS9之后的collection长按拖动图片功能、优化图片选择器中的卡顿现象,去除在collectioncell中绘制图片代码,加快加载速度,以下代码已去除
//修正图片方向
UIImage *targetImg = [weakSelf fixOrientation:result];
//缩小图片
targetImg = [weakSelf reSizeImage:targetImg ForSize:target];
复制代码
真机测试效果更佳,大家用真机测试吧,代码都在GitHub中,注释很详细,大家可以去看,觉得有用记得点个star~