1、最新最详细代码都在github上,欢迎下载。github地址:https://github.com/honeycao/ACMediaFrame
2、代码细节问题可以参考简书文章:http://www.jianshu.com/p/9ff1e8e68a21
3、框架主要功能:
3.1、本地图片视频选择、拍照录制等全封装使用
3.2、主体是一个展示的页面,可添加到任何地方,同时处理好了一切布局。
3.3、选择图片和图片预览等用到了TZImagePickerController和MWPhotoBrowser两个第三方
3.4、自定义媒体model,存储图片、视频上传数据类型,如:NSData或视频路径。
3.5、结果:添加该框架到任意页面之后不再需要做其他操作,只需要写上文件上传的网络请求即可。
写在前面的话
- 更新:框架上的东西最近有所改动,更具体的使用和功能可以参考GitHub源代码
- 本文章是基于自己封装的一个媒体框架来写的,比较粗糙,时间短,待改进。具体内容可以到github中查看:ACMediaFrame
- 下面没有涉及框架的使用,使用比较简单方便,可以看github就都清楚了,主要是罗列一些具体功能点,和重点的解析(其实都算不上重点勒。都是简单的东西,然后加以改进完善而已,所以看起来应该没什么难度的)
- 框架主体:本地选择图片视频、拍摄图片视频;布局展示图片视频,可删除;直接存储了供上传的数据类型,所以距离上传就一步之遥(发送请求而已)。
主要内容
本媒体库系列包括:其一,本地图片、视频、拍照、录像等的选择;其二,媒体文件布局展示操作等;其三:媒体文件上传操作简易化。
一、媒体文件选择
大部分项目都有图片选择和拍照等功能,更甚至录像和视频等,对于多次用到这些功能,借此机会进行基础封装。选择照片用到了第三方
TZImagePickerController
进行多图选择。
1、TZImagePickerController
的简单使用
这个框架主要用来选择多张图片,下面是简单使用的代码,也是媒体系列框架所用到的,更详细可以点击链接去查看。对于其代理方法中获取的图片或视频的处理,在后面会详细介绍。
github通道:TZImagePickerController
//初始化 并设置代理 和 最大选择张数
TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:9 delegate:self];
///是否 在相册中显示拍照按钮
imagePickerVc.allowTakePicture = NO;
///是否可以选择显示原图
imagePickerVc.allowPickingOriginalPhoto = NO;
///是否 在相册中可以选择视频
imagePickerVc.allowPickingVideo = YES;
[self presentViewController:imagePickerVc animated:YES completion:nil];
#pragma mark - TZImagePickerController Delegate
//处理从相册单选或多选的照片
- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto{
}
///选取视频后的回调
- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingVideo:(UIImage *)coverImage sourceAssets:(id)asset {
}
2、系统方法UIImagePickerController
的使用
-
基础枚举类型解析
//picker资源类型
typedef NS_ENUM(NSInteger, UIImagePickerControllerSourceType) {
UIImagePickerControllerSourceTypePhotoLibrary, // 媒体库(所有媒体文件夹:视频和图片)
UIImagePickerControllerSourceTypeCamera, //相机
UIImagePickerControllerSourceTypeSavedPhotosAlbum //相册
}
//相机捕获类型
typedef NS_ENUM(NSInteger, UIImagePickerControllerCameraCaptureMode) {
UIImagePickerControllerCameraCaptureModePhoto, //拍照 (默认)
UIImagePickerControllerCameraCaptureModeVideo //录像
}
//进入相册转场动画
typedef NS_ENUM(NSInteger, UIModalTransitionStyle) {
UIModalTransitionStyleCoverVertical, //默认,竖直方向推出
UIModalTransitionStyleFlipHorizontal,//水平方向翻转
UIModalTransitionStyleCrossDissolve,//溶解,没有太多动画
UIModalTransitionStylePartialCurl //上下翻页
};
- 打开相机:拍照或录像
/** 打开相机 */
- (void)openCamera {
UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera;
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]){
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
//设置拍照后的图片可被编辑
picker.allowsEditing = YES;
picker.sourceType = sourceType;
/* 如果是录像
picker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo;
picker.videoQuality = UIImagePickerControllerQualityTypeMedium; //录像质量
picker.videoMaximumDuration = 600.0f; //录像最长时间
*/
[self presentViewController:picker animated:YES completion:nil];
}else{
//不支持拍照或模拟器系列
}
}
- 相册或所有媒体文件夹
- (void)openPhotos {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
//转场动画
picker.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
/* 选择所有媒体文件夹
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary
*/
picker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:picker.sourceType];
picker.allowsEditing = YES;
[self presentViewController:picker animated:YES completion:nil];
}
-
代理方法
- 代理方法回调的 info 字典key解析
//媒体类型 分为: @"public.movie" 和 @"public.image" UIImagePickerControllerMediaType //原图 (视频和录像都没有) UIImagePickerControllerOriginalImage //编辑后的图片(前提是设置了 picker.allowsEditing = YES ,不然没有这个),视频和录像没有这个 UIImagePickerControllerEditedImage //视频录像的URL UIImagePickerControllerMediaURL //原件的URL,从本地选取的才有,也就是说拍照和录像都不存在这个 UIImagePickerControllerReferenceURL
#pragma mark - UIImagePickerController Delegate
///拍照、选视频图片、录像 后的回调(这种方式选择视频时,会自动压缩,但是很耗时间)
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
//todo: 后面有具体处理方法
}
二、布局、展示
布局的话,也不是太复杂,看图也知道我的布局,具体内容请看github中源码,反正都是直接封装好的。至于布局,用到了第三方
MWPhotoBrowser
,可以大图显示图片和视频。
1、MWPhotoBrowser
的简单使用
github通道:MWPhotoBrowser
NSMutableArray *photos = [NSMutableArray array];
//初始化 并 设置代理
MWPhotoBrowser *browser = [[MWPhotoBrowser alloc] initWithDelegate:self];
//是否显示活动按钮(分享等操作,默认为 YES)
browser.displayActionButton = NO;
// 是否一直显示导航栏控制器(默认为NO,点击图片消失,再点击又出现,如果有图片名,那么和导航栏一样)
browser.alwaysShowControls = NO;
//是否在每张图片右上角显示一个图片选中的按钮(默认NO)
browser.displaySelectionButtons = NO;
//是否显示底部工具条的左右箭头,多张图才有效果,箭头也就是用来翻页的(默认NO)
browser.displayNavArrows = NO;
//图片填满屏幕,依据最小边来定(默认YES)
browser.zoomPhotosToFill = YES;
browser.startOnGrid = NO;
browser.enableGrid = YES;
//添加图片数组:数据必须都是 MWPhoto 类型的
//添加本地图片
[photos addObject:[MWPhoto photoWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"photo2l" ofType:@"jpg"]]]];
//添加url图片
[photos addObject:[MWPhoto photoWithURL:[NSURL URLWithString:@"http://farm4.static.flickr.com/3629/3339128908_7aecabc34b.jpg"]]];
//添加视频
//视频封面图
MWPhoto *video = [MWPhoto photoWithURL:[NSURL URLWithString:@"https://scontent.cdninstagram.com/hphotos-xpt1/t51.2885-15/e15/11192696_824079697688618_1761661_n.jpg"]];
//视频内容url
video.videoURL = [[NSURL alloc] initWithString:@"https://scontent.cdninstagram.com/hphotos-xpa1/t50.2886-16/11200303_1440130956287424_1714699187_n.mp4"];
[photos addObject:video];
//设置大图时 首先显示的图片(也就是photos数组的第几张,一定要在设置了photos数组之后设置,不然是没有作用的)
[browser setCurrentPhotoIndex:1];
//必须是 push
[self.navigationController pushViewController:browser animated:YES];
2、代理方法
#pragma mark - <MWPhotoBrowserDelegate>
//图片总数
- (NSUInteger)numberOfPhotosInPhotoBrowser:(MWPhotoBrowser *)photoBrowser {
return self.photos.count;
}
//下标对应的图片数据源
- (id <MWPhoto>)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index {
if (index < self.photos.count) {
return [self.photos objectAtIndex:index];
}
return nil;
}
三、上传等图片信息处理
通过前面步骤得到了数据,并知道怎么显示了,那么接下来就是数据处理和上传的准备。为此单独准备了一个model来存储媒体信息。通过这个模型我们就可以分别得到图片显示的image,和视频显示的url,最主要也存储好了上传的类型,图片上传NSData,视频较大一般都是上传本地路径,不会直接上传NSData。
#import <Photos/Photos.h>
@interface ACMediaModel : NSObject
/** 媒体名字 */
@property (nonatomic, copy) NSString *name;
/** 媒体上传格式 图片是NSData,视频主要是路径名,也有NSData */
@property (nonatomic, strong) id uploadType;
//兼容 MWPhotoBrowser 的附加属性
/** 媒体照片 */
@property (nonatomic, strong) UIImage *image;
/** iOS8 之后的媒体属性 */
@property (nonatomic, strong) PHAsset *asset;
/** 是否属于可播放的视频类型 */
@property (nonatomic, assign) BOOL isVideo;
/** 视频的URL */
@property (nonatomic, strong) NSURL *mediaURL;
@end
四、根据得到的媒体数据转化存储为自定义的ACMediaModel
模型
这个算的上是一个比较关键的数据处理步骤了,分为2种,分别是
UIImagePickerController
和TZImagePickerController
得到的数据处理,涉及到PHAsset
的解析和URL、Image的处理
PHAsset是iOS8之后<Photos/Photos.h>库下的API,对于PHAsset具体解析可以参考:ALAsset/PHAsset 中的图片和视频文件,比较详细。
在封装的方法中,确并没有完全用上上面的方法,主要是PHAsset解析视频时,异步加载回调需要等待一段时间,这个就不太符合要求了,所以换了如下方法来处理
/**
根据 PHAsset 来获取 媒体文件(视频或图片)相关信息:文件名、文件上传类型(data 或 path)
@param asset PHAsset对象
@param completion 成功回调
*/
+ (void)getMediaInfoFromAsset: (PHAsset *)asset completion: (void(^)(NSString *name, id pathData))completion {
if (!asset) {
return;
}
NSString *mediaName;
__block NSData *data;
if (asset.mediaType == PHAssetMediaTypeImage) {
//图片文件名
mediaName = [self getMediaNameWithPHAsset:asset extensionName:@"Image.png"];
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.version = PHImageRequestOptionsVersionCurrent;
//返回图片的质量类型 (效率高,质量低)
options.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;
//同步请求获取iCloud图片(默认为NO)
//options.synchronous = YES;
[[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
data = [NSData dataWithData:imageData];
if (completion && data.length > 0) {
completion(mediaName, data);
}
}];
}
else if (asset.mediaType == PHAssetMediaTypeVideo ||
asset.mediaSubtypes == PHAssetMediaSubtypePhotoLive) {
//视频文件名
mediaName = [self getMediaNameWithPHAsset:asset extensionName:@"IMG.MOV"];
NSString *videoPath = [NSTemporaryDirectory() stringByAppendingString:mediaName];
BOOL success = [[NSFileManager defaultManager] fileExistsAtPath:videoPath];
//当前处理方式:本地的视频 直接返回路径,非本地的也不存储到本地,直接返回data
if (success) {
!completion ? : completion(mediaName, videoPath);
}else{
NSData *videoData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:videoPath]];
!completion ? : completion(mediaName, videoData);
}
}
}
上面的图片解析是根据PHAsset方法来的,但是刚开始出现同时解析多张,回调缺少了数据的问题,后来没怎么修改,但是这个问题又不存在了,所以到时候看看需要需要也把这个方法替换掉。。。
经过之前一系列数据的处理,基本都属于ACMediaModel
属性范围,对此就基本完成了显示的媒体数据源的添加,根据这个ACMediaModel
,我们可以展示图片视频、删除并且上传,对于上传我们所需要添加到request的header中去的,就是ACMediaModel
中的uploadType
属性。
五、结语
- 一开始讲到了媒体文件选择,这个都很基础,列出来做个参考
- 其次是涉及到
TZImagePickerController
和MWPhotoBrowser
两个第三方库的基本用法,以及代理方法,但是代理方法中怎么处理,也一直没说,简单点就是通过第四步的方法处理PHAsset或者info,然后转化为Model存储、展示等。具体可以看代码中。 - 写这个的初衷是连续多次用到这个知识,每次都去写布局、方法处理,觉得很麻烦,所以就想着写到一起来,虽然PHAsset在这里没用到详细,但是一开始研究的时候是翻阅了很多相关知识,而且研究下去也是有很多新的知识,只是最后发现有了不足的地方才改换简单的方法。
- 在本文章中并没有说太多框架使用的方法,只是对其中一些方法的罗列和简单分析。具体框架使用可以到github中查看。
- github地址:ACMediaFrame还是那句话:写的不好,欢迎探讨、指正。I am a rookie ,I am not God (有建议或想法请q:331864805 ,你的点赞是我最大的动力)
作者:大都市里小刁民
链接:https://www.jianshu.com/p/9ff1e8e68a21
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。