iOS开发 自定义相册键盘
现在很多app都有用到相册选择等功能,网上也已经有了很多封装好了的第三方库,但是最近项目中,设计师突发奇想,想要节省用户选择成本,让我们实现相册键盘,不用跳转新的页面可以直接选择照片或者视频,类似于图中的样式:
图1.0然后第一个想法,网上找轮子,然后找了一圈,并没有发现适用的,只好自己实现了。
我用的方法是利用UICollectionView实现,接下来贴上代码。
1.首先做好准备工作,在pod文件中导入下列第三方库:
pod 'YBImageBrowser',' ~> 2.1.5'
pod 'SDWebImage',' ~> 4.4.6'
pod 'Toast'
pod 'Masonry',' ~> 1.1.0'
pod 'SJVideoPlayer'
这些大都是常用的第三方库,从上到下的功能分别是:图片查看、图片加载、Toast提示、页面布局、视频播放。
2.然后在info.plist文件中添加相册权限提示:
图23.开始写代码,导入相应头文件和设置好相应的协议还有数据
#import "ViewController.h"
#import <SDWebImage/UIImageView+WebCache.h>
#import "YBImageBrowser.h"
#import <Photos/Photos.h>
#import "Masonry.h"
#import "UIView+Toast.h"
#import "HobbiesCollectionViewCell.h"
#import "TZImagePickerController.h"
#import "YJVideoController.h"
#import "VideoPlayViewController.h"
@interface ViewController ()<UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout,UINavigationControllerDelegate,UIImagePickerControllerDelegate,YBImageBrowserDataSource,UIGestureRecognizerDelegate,TZImagePickerControllerDelegate>
{
UICollectionView*myCollectionView; //相册瀑布流
NSMutableArray*imageArray; //图片数组
NSMutableArray*selectArray; //图片选择数组
NSMutableArray*phArray; //媒体数据数组
NSIntegernums; //最大可选择的照片数量
NSInteger IorV; //视频还是照片 -1:未选择 0:照片 1:视频
UIView*bottomV; //相册所在的父视图
UIView*toolView; //相册上方的工具视图(可自定义)
UISwipeGestureRecognizer* recognizerUp; //上滑手势
UISwipeGestureRecognizer* recognizerDown; //下拉手势
BOOLisTop; //是否滑动到顶部
BOOLUPorDown; //是否是在全屏状态
NSIntegerpage; //页码
BOOLready; //是否准备好再次刷新
}
@property(nonatomic,strong) UIImagePickerController *imagePicker;
@end
4.开始进入时候检查权限
-(void)checkPermissions
{
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status == PHAuthorizationStatusAuthorized) {
dispatch_main_async_safe(^{
[selfloadImageArray];
});
}else{
//未获取相册权限
[self showAlrtToSetting];
}
}];
}
/**
检测到未开启相册权限之后的提醒
*/
-(void) showAlrtToSetting
{
UIAlertController* alert = [UIAlertControlleralertControllerWithTitle:@"开启相册权限"message:@"打开相册权限,上传您喜欢的图片"preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* cancelAction = [UIAlertActionactionWithTitle:@"再看看"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction*_Nonnullaction) {
}];
UIAlertAction * setAction = [UIAlertAction actionWithTitle:@"打开" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action)
{
NSURL* url = [NSURLURLWithString:UIApplicationOpenSettingsURLString];
dispatch_async(dispatch_get_main_queue(), ^{
if([[UIApplicationsharedApplication]canOpenURL:url])
{
[[UIApplicationsharedApplication]openURL:urloptions:@{}completionHandler:^(BOOLsuccess) {
dispatch_main_async_safe(^{
[selfloadImageArray];
});
}];
}
});
}];
[alertaddAction:cancelAction];
[alertaddAction:setAction];
[self presentViewController:alert animated:YES completion:nil];
}
5.然后初始化视图
-(void)initUI
{
self.view.backgroundColor = [UIColor lightGrayColor];
nums=0;
IorV= -1;
ready=YES;
isTop=NO;
page=0;
toolView = [[UIView alloc] initWithFrame:CGRectMake(0, HEIGHT-221-kSafeAreaBottomHeight-44, WIDTH, 44)];
toolView.backgroundColor = [UIColor whiteColor];
toolView.tag=88;
[self.viewaddSubview:toolView];
bottomV= [[UIViewalloc]init];
[self.viewaddSubview:bottomV];
[bottomV mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.view);
make.top.equalTo(toolView.mas_bottom);
make.height.mas_equalTo(HEIGHT+221+kSafeAreaBottomHeight);
}];
//创建一个layout布局类
UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc]init];
//设置布局方向为垂直流布局
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
//设置每个item的大小为100*100
layout.itemSize=CGSizeMake(WIDTH/4-1,WIDTH/4-1);
//创建collectionView 通过一个布局策略layout来创建
myCollectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, 221+kSafeAreaBottomHeight) collectionViewLayout:layout];
myCollectionView.delegate = self;
myCollectionView.dataSource = self;
myCollectionView.scrollEnabled = YES;
myCollectionView.bounces = NO;
myCollectionView.backgroundColor = [UIColor blackColor];
//注册Cell
[myCollectionView registerNib:[UINib nibWithNibName:@"HobbiesCollectionViewCell" bundle: [NSBundle mainBundle]] forCellWithReuseIdentifier:@"HobbiesCollectionViewCell"];
[bottomV addSubview:myCollectionView];
recognizerUp= [[UISwipeGestureRecognizeralloc]initWithTarget:selfaction:@selector(handleSwipeFrom:)];
recognizerUp.direction = UISwipeGestureRecognizerDirectionUp;
recognizerUp.delegate = self;
[self.view addGestureRecognizer:recognizerUp];
recognizerDown= [[UISwipeGestureRecognizeralloc]initWithTarget:selfaction:@selector(handleSwipeFrom:)];
recognizerDown.direction = UISwipeGestureRecognizerDirectionDown;
recognizerDown.delegate = self;
[self.view addGestureRecognizer:recognizerDown];
}
6.加载本地照片和视频数据
-(void)loadImageArray
{
[self.view makeToastActivity:CENTER];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// 处理耗时操作的代码块
phArray= [NSMutableArrayarray];
imageArray= [NSMutableArrayarray];
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
PHFetchResult*assetsFetchResults = [PHAssetfetchAssetsWithOptions:options];
for(PHAsset*assetinassetsFetchResults)
{
//判断本地媒体数据是照片类型和视频类型,就加入到phArray数组中
if (asset.mediaType == PHAssetMediaTypeImage || asset.mediaType == PHAssetMediaTypeVideo)
{
[phArrayaddObject:asset];
}
}
phArray=(NSMutableArray *)[[phArray reverseObjectEnumerator] allObjects]; //数组倒序排列
//加载前两百条数据(防止加载耗时过长)
NSIntegercounts =phArray.count;
if(counts>200)
{
counts =200;
}
for(inti=0;i
{
PHAsset*asset = [phArrayobjectAtIndex:i];
PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
/** resizeMode:对请求的图像怎样缩放。有三种选择:None,默认加载方式;Fast,尽快地提供接近或稍微大于要求的尺寸;Exact,精准提供要求的尺寸。 deliveryMode:图像质量。有三种值:Opportunistic,在速度与质量中均衡;HighQualityFormat,不管花费多长时间,提供高质量图像;FastFormat,以最快速度提供好的质量。
这个属性只有在 synchronous 为 true 时有效。
*/
option.resizeMode = PHImageRequestOptionsResizeModeFast;//控制照片尺寸
option.deliveryMode=1;//控制照片质量
option.synchronous=YES;
option.networkAccessAllowed=YES;
//param:targetSize 即你想要的图片尺寸,若想要原尺寸则可输入PHImageManagerMaximumSize
[[PHCachingImageManager defaultManager] requestImageForAsset:asset targetSize:CGSizeMake(WIDTH/4, HEIGHT/4) contentMode:PHImageContentModeAspectFit options:option resultHandler:^(UIImage * _Nullable image, NSDictionary * _Nullable info) {
NSString*types =@"0"; //0:照片 1:视频
if(asset.mediaType==PHAssetMediaTypeImage)
{
types =@"0";
}
else
{
types =@"1";
}
NSDictionary*dic =@{@"image":image,@"type":types,@"times":@"0"};
[imageArrayaddObject:dic];
}];
}
//初始化是否选择的数组
selectArray= [NSMutableArrayarray];
for(inti=0;i
{
[selectArrayaddObject:@"0"];
}
//通知主线程刷新
dispatch_async(dispatch_get_main_queue(), ^{
//回调或者说是通知主线程刷新
[myCollectionViewreloadData];
[self.viewhideToastActivity];
});
});
}
7.上滑和下拉操作手势实现方法
- (void)handleSwipeFrom:(UISwipeGestureRecognizer*)recognizer
{
if(recognizer.direction ==UISwipeGestureRecognizerDirectionUp) //上拉
{
if(!UPorDown)
{
CGFloatyy =toolView.frame.origin.y;
if(yy>100)
{
[UIView animateWithDuration:0.5 animations:^{
toolView.transform=CGAffineTransformMakeTranslation(0, -yy+kStatusBarHeight);
bottomV.transform=CGAffineTransformMakeTranslation(0, -yy+kStatusBarHeight);
myCollectionView.frame=CGRectMake(0,0,WIDTH,HEIGHT-44-kStatusBarHeight);
}completion:^(BOOLfinished){
}];
}
UPorDown=YES;
}
}
else if(recognizer.direction ==UISwipeGestureRecognizerDirectionDown) //下滑
{
if(UPorDown)
{
if(isTop)
{
[UIView animateWithDuration:0.5 animations:^{
toolView.transform = CGAffineTransformMakeTranslation(0, 0);
bottomV.transform = CGAffineTransformMakeTranslation(0, 0);
}completion:^(BOOLfinished){
myCollectionView.frame=CGRectMake(0,0,WIDTH,221+kSafeAreaBottomHeight);
}];
UPorDown=NO;
}
}
}
}
8.下拉加载下一页(200条)的数据
-(void)footerClick
{
if(phArray.count<200)
{
return;
}
ready=NO;
NSIntegercounts =phArray.count;
NSIntegernowCounts =200+page*200;
if(nowCounts < counts)
{
if(nowCounts < counts -200)
{
counts = nowCounts +200;
}
}
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// 处理耗时操作的代码块
for(NSIntegeri=nowCounts;i
{
PHAsset*asset = [phArrayobjectAtIndex:i];
PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
/** resizeMode:对请求的图像怎样缩放。有三种选择:None,默认加载方式;Fast,尽快地提供接近或稍微大于要求的尺寸;Exact,精准提供要求的尺寸。 deliveryMode:图像质量。有三种值:Opportunistic,在速度与质量中均衡;HighQualityFormat,不管花费多长时间,提供高质量图像;FastFormat,以最快速度提供好的质量。
这个属性只有在 synchronous 为 true 时有效。
*/
option.resizeMode = PHImageRequestOptionsResizeModeFast;//控制照片尺寸
option.deliveryMode=1;//控制照片质量
option.synchronous=YES;
option.networkAccessAllowed=YES;
//param:targetSize 即你想要的图片尺寸,若想要原尺寸则可输入PHImageManagerMaximumSize
[[PHCachingImageManager defaultManager] requestImageForAsset:asset targetSize:CGSizeMake(WIDTH/4, HEIGHT/4) contentMode:PHImageContentModeAspectFit options:option resultHandler:^(UIImage * _Nullable image, NSDictionary * _Nullable info) {
NSString*types =@"0"; //0:照片 1:视频
if(asset.mediaType==PHAssetMediaTypeImage)
{
types =@"0";
}
else
{
types =@"1";
}
NSDictionary*dic =@{@"image":image,@"type":types,@"times":@"0"};
[imageArrayaddObject:dic];
[selectArrayaddObject:@"0"];
}];
}
//通知主线程刷新
dispatch_async(dispatch_get_main_queue(), ^{
//回调或者说是通知主线程刷新
[myCollectionViewreloadData];
[self.viewhideToastActivity];
page++;
ready=YES;
});
});
}
9.手势协议的实现(防止UICollectionView的滚动事件和手势冲突)
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer
{
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldReceiveTouch:(UITouch*)touch
{
if([NSStringFromClass([touch.view class]) isEqualToString:@"UIView"])
{
UIView*vies = touch.view;
if(vies.tag==88)
{
isTop=YES;
}
}
if([NSStringFromClass([touch.view class]) isEqual:@"UICollectionView"])
{
returnNO;
}
else
{
returnYES;
}
}
10.滚动过程中的监听
- (void)scrollViewDidScroll:(UIScrollView*)scrollView
{
CGPointlocalPoint = scrollView.contentOffset;
if(localPoint.y<=0)
{
isTop=YES;
}
else
{
isTop=NO;
if(localPoint.y>(page+1)*3800) //还未到达最底部就开始加载下200条,预防卡顿
{
if(ready)
{
[selffooterClick];
}
}
}
}
11.CollectionView协议方法实现
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)collectionView
{
return1;
}
/**
设置CollectionView每组所包含的个数
*/
- (NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section
{
return imageArray.count;
}
/**
设置CollectionCell的内容
*/
- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath
{
HobbiesCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"HobbiesCollectionViewCell"forIndexPath:indexPath];
cell.bgImageView.image = [imageArray[indexPath.row] objectForKey:@"image"];
if([[imageArray[indexPath.row] objectForKey:@"type"] isEqualToString:@"0"]) //照片类型,隐藏视频相关控件
{
cell.playImageView.hidden =YES;
cell.playMengView.hidden =YES;
cell.playTimeLabel.hidden =YES;
}
else //视频类型
{
cell.playImageView.hidden =NO;
cell.playMengView.hidden =NO;
cell.playTimeLabel.hidden =NO;
if([[imageArray[indexPath.row] objectForKey:@"times"] isEqualToString:@"0"])
{ //异步获取视频时长
dispatch_async(dispatch_get_global_queue(0,0), ^{
// 处理耗时操作的代码块...
PHAsset *asset = [phArray objectAtIndex:indexPath.row];
__blockintseconds;
[[TZImageManager manager] getVideoWithAsset:asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
AVAsset *avasset = playerItem.asset;
AVURLAsset *urlAsset = (AVURLAsset *)avasset;
CMTime time = [urlAsset duration];
seconds = (int)time.value/time.timescale;
NSDictionary *dic =@{@"image":[imageArray[indexPath.row] objectForKey:@"image"],@"type":[imageArray[indexPath.row] objectForKey:@"type"],@"times":[NSString stringWithFormat:@"%d",seconds]};
[imageArray replaceObjectAtIndex:indexPath.row withObject:dic];
}];
//通知主线程刷新
dispatch_async(dispatch_get_main_queue(), ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f* NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[myCollectionView reloadData];
});
});
});
}
else
{
cell.playTimeLabel.text = [selftimeEdit:[NSString stringWithFormat:@"%@",[imageArray[indexPath.row] objectForKey:@"times"]]];
}
}
//处理选择后的显示
if([selectArray[indexPath.row] isEqualToString:@"0"])
{
cell.selectImageView.backgroundColor = [UIColor clearColor];
cell.cellNumLabel.text =@"";
cell.selectImageView.image = [UIImage imageNamed:@"noSelect"];
}
else
{
cell.selectImageView.backgroundColor = [UIColor colorWithRed:(255)/255.0green:(175)/255.0blue:(33)/255.0alpha:1.0];
cell.selectImageView.image =nil;
cell.cellNumLabel.text = selectArray[indexPath.row];
}
cell.selectImageView.hidden =NO;
cell.selectBtn.tag = indexPath.row;
[cell.selectBtn addTarget:selfaction:@selector(selectBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
returncell;
}
/**
定义每个UICollectionView的大小
*/
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath
{
return CGSizeMake(WIDTH/4-1,WIDTH/4-1);
}
/**
定义整个CollectionViewCell与整个View的间距
*/
- (UIEdgeInsets)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(1, 1, 1, 1);//(上、左、下、右)
}
/**
定义每个UICollectionView的横向间距
*/
- (CGFloat)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return0;
}
/**
定义每个UICollectionView的纵向间距
*/
- (CGFloat)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return0;
}
/**
点击CollectionView触发事件
*/
-(void)collectionView:(UICollectionView*)collectionView didSelectItemAtIndexPath:(NSIndexPath*)indexPath
{
if([[imageArray[indexPath.row]objectForKey:@"type"]isEqualToString:@"0"])//照片
{
[selflookImage:indexPath.row];
}
else
{
[selflookVideo:indexPath.row];
}
}
/**
设置CollectionViewCell是否可以被点击
*/
- (BOOL)collectionView:(UICollectionView*)collectionView shouldSelectItemAtIndexPath:(NSIndexPath*)indexPath
{
return YES;
}
12.时间格式处理
-(NSString*)timeEdit:(NSString*)times
{
inttimeNum = [timesintValue];
if(timeNum<10)
{
return[NSStringstringWithFormat:@"00:0%d",timeNum];
}
elseif(timeNum<60)
{
return[NSStringstringWithFormat:@"00:%d",timeNum];
}
else
{
inta = timeNum%60;
intb = timeNum/60;
if(a<10)
{
if(b<10)
{
return[NSStringstringWithFormat:@"0%d:0%d",b,a];
}
else
{
return[NSStringstringWithFormat:@"%d:0%d",b,a];
}
}
else
{
if(b<10)
{
return[NSStringstringWithFormat:@"0%d:%d",b,a];
}
else
{
return[NSStringstringWithFormat:@"%d:%d",b,a];
}
}
}
}
13.查看图片
-(void)lookImage:(NSInteger)currentIndex
{
YBImageBrowser *browser = [YBImageBrowser new];
browser.dataSource=self;
browser.currentIndex= currentIndex;
//展示
[browsershow];
}
14.查看视频(单独写了一个查看视频文件,详情请看下方git链接)
-(void)lookVideo:(NSInteger)currentIndex
{
PHAsset*phAsset =phArray[currentIndex];
if(phAsset.mediaType==PHAssetMediaTypeVideo) {
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
options.version = PHImageRequestOptionsVersionCurrent;
options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
PHImageManager *manager = [PHImageManager defaultManager];
[managerrequestAVAssetForVideo:phAssetoptions:optionsresultHandler:^(AVAsset*_Nullableasset,AVAudioMix*_NullableaudioMix,NSDictionary*_Nullableinfo) {
AVURLAsset*urlAsset = (AVURLAsset*)asset;
NSURL*url = urlAsset.URL;
NSString*urls = [NSStringstringWithFormat:@"%@",url];
VideoPlayViewController *playVC = [[VideoPlayViewController alloc] init];
playVC.url= urls;
[self presentViewController:playVC animated:YES completion:nil];
}];
}
}
15.选择视频或照片实现
-(void)selectBtnClicked:(UIButton*)sender
{
if(nums==0)
{
IorV= -1;
}
if([[imageArray[sender.tag] objectForKey:@"type"] isEqualToString:@"0"]) //照片
{
if(IorV==1)
{
[self.viewmakeToast:@"视频和照片只能上传一种!"duration:2position:CENTER];
return;
}
IorV=0;
if([selectArray[sender.tag]isEqualToString:@"0"])
{
if(nums==9)
{
[self.viewmakeToast:@"最多只能选择9张照片!"duration:2position:CENTER];
return;
}
nums++;
[selectArray replaceObjectAtIndex:sender.tag withObject:[NSString stringWithFormat:@"%ld",(long)nums]];
[myCollectionViewreloadData];
}
else
{
if([selectArray[sender.tag]integerValue] ==9)//是最后一个只要刷新最后一条的数据
{
[selectArrayreplaceObjectAtIndex:sender.tagwithObject:@"0"];
[myCollectionViewreloadData];
}
else
{
for(inti=0;i
{
NSIntegerindexs = [selectArray[i]integerValue];
if(indexs>[selectArray[sender.tag]integerValue])
{
[selectArray replaceObjectAtIndex:i withObject:[NSString stringWithFormat:@"%ld",(long)indexs]];
}
}
[selectArrayreplaceObjectAtIndex:sender.tagwithObject:@"0"];
[myCollectionViewreloadData];
}
nums--;
}
}
else
{
if(IorV==0)
{
[self.viewmakeToast:@"视频和照片只能上传一种!"duration:2position:CENTER];
return;
}
IorV=1;
if([selectArray[sender.tag]isEqualToString:@"0"])
{
if(nums==1)
{
[self.viewmakeToast:@"最多只能选择1个视频!"duration:2position:CENTER];
return;
}
nums++;
[selectArray replaceObjectAtIndex:sender.tag withObject:[NSString stringWithFormat:@"%ld",(long)nums]];
[myCollectionViewreloadData];
}
else
{
[selectArray replaceObjectAtIndex:sender.tag withObject:@"0"];
[myCollectionViewreloadData];
nums-- ;
}
}
}
16.YBImageBrowserDataSource 代理实现赋值数据(图片查看)
- (NSUInteger)yb_numberOfCellForImageBrowserView:(YBImageBrowserView*)imageBrowserView {
returnphArray.count;
}
- (id)yb_imageBrowserView:(YBImageBrowserView*)imageBrowserView dataForCellAtIndex:(NSUInteger)index {
YBImageBrowseCellData *data = [YBImageBrowseCellData new];
data.phAsset=phArray[index];
returndata;
}
备注:目前根据项目,最多只能选择9张图片,并且图片和视频只能选择一种,所以做了限制。选择完成后,循环遍历selectArray既可获得所选的文件数据,代码大致如下:
{
imageUrlArray = [NSMutableArray array];
NSMutableArray *postImgArray = [NSMutableArray array];
for(inti=0;i
{
if(![selectArray[i] isEqualToString:@"0"])
{
PHAsset *asset = phArray[i];
if(IorV==1) //视频
{
//视频只能选择一个,直接这里转视频,然后上传
if(asset.mediaType == PHAssetMediaTypeVideo)
{
[[TZImageManager manager] getVideoWithAsset:asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
AVAsset *avasset = playerItem.asset;
AVURLAsset *urlAsset = (AVURLAsset *)avasset;
NSURL *urls = urlAsset.URL;
CMTime time = [urlAsset duration];
intseconds = ceil(time.value/time.timescale);
NSLog(@"视频时长:%d",seconds);
NSData *data = [NSData dataWithContentsOfURL:urls];
NSInteger videoSize = data.length/1024;
floatsizes = (float)videoSize/1024;
NSLog(@"视频大小:%.2f M",sizes);
/*
创建AVAssetExportSession对象
压缩的质量
AVAssetExportPresetLowQuality 最low的画质最好不要选择实在是看不清楚
AVAssetExportPresetMediumQuality 使用到压缩的话都说用这个
AVAssetExportPresetHighestQuality 最清晰的画质
*/
AVAssetExportSession * session = [[AVAssetExportSession alloc] initWithAsset:avasset presetName:AVAssetExportPreset960x540];
//优化网络
session.shouldOptimizeForNetworkUse =YES;
//转换后的格式
//拼接输出文件路径 为了防止同名 可以根据日期拼接名字 或者对名字进行MD5加密
NSString* path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES) lastObject] stringByAppendingPathComponent:@"hello.mp4"];
//判断文件是否存在,如果已经存在删除
[[NSFileManager defaultManager]removeItemAtPath:path error:nil];
//设置输出路径
session.outputURL = [NSURL fileURLWithPath:path];
//设置输出类型 这里可以更改输出的类型 具体可以看文档描述
session.outputFileType = AVFileTypeMPEG4;
session.videoComposition = [selfgetVideoComposition:urlAsset];
[session exportAsynchronouslyWithCompletionHandler:^{
//压缩完成
if(session.status==AVAssetExportSessionStatusCompleted) {
//在主线程中刷新UI界面,弹出控制器通知用户压缩完成
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"导出完成");
NSURL *beforeurl = session.outputURL;
NSData *datass = [NSData dataWithContentsOfURL:beforeurl];
NSInteger videoSizess = datass.length/1024;
floatsizess = (float)videoSizess/1024;
NSLog(@"压缩完毕,压缩后大小 %.2f MB",sizess);
//去上传视频,地址为beforeurl
});
}
}];
}];
break;
}
}
else
{
//照片可以传多张,所以循环添加进postImgArray
PHImageManager *manager = [PHImageManager defaultManager];
PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
/** resizeMode:对请求的图像怎样缩放。有三种选择:None,默认加载方式;Fast,尽快地提供接近或稍微大于要求的尺寸;Exact,精准提供要求的尺寸。 deliveryMode:图像质量。有三种值:Opportunistic,在速度与质量中均衡;HighQualityFormat,不管花费多长时间,提供高质量图像;FastFormat,以最快速度提供好的质量。
这个属性只有在 synchronous 为 true 时有效。
*/
option.resizeMode = PHImageRequestOptionsResizeModeFast;//控制照片尺寸
option.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;//控制照片质量
option.synchronous =YES;
option.networkAccessAllowed =YES;
[manager requestImageForAsset:phArray[i] targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:option resultHandler:^(UIImage *resultImage, NSDictionary *info)
{
[postImgArray addObject:resultImage];
if(postImgArray.count == nums)
{
//当postImgArray的数量和开始记录的选中数量相等的时候,开始上传操作
}
}];
}
}
}
}
大致思路是如此,第一次写简书,比较乱,大家勿怪,下方贴上github链接,可以下载下来看demo参考,顺便给个star,感谢🙏。祝大家生活愉快,永不脱发。