現(xiàn)在很多app都有用到相冊(cè)選擇等功能,網(wǎng)上也已經(jīng)有了很多封裝好了的第三方庫(kù),但是最近項(xiàng)目中,設(shè)計(jì)師突發(fā)奇想,想要節(jié)省用戶選擇成本,讓我們實(shí)現(xiàn)相冊(cè)鍵盤,不用跳轉(zhuǎn)新的頁(yè)面可以直接選擇照片或者視頻,類似于圖中的樣式:

然后第一個(gè)想法,網(wǎng)上找輪子,然后找了一圈,并沒有發(fā)現(xiàn)適用的,只好自己實(shí)現(xiàn)了。
我用的方法是利用UICollectionView實(shí)現(xiàn),接下來貼上代碼。
1.首先做好準(zhǔn)備工作,在pod文件中導(dǎo)入下列第三方庫(kù):
? pod ?'YBImageBrowser',' ~> 2.1.5'????????
? pod ?'SDWebImage',' ~> 4.4.6'
? pod ?'Toast'
? pod ?'Masonry',' ~> 1.1.0'
? pod ?'SJVideoPlayer'
這些大都是常用的第三方庫(kù),從上到下的功能分別是:圖片查看、圖片加載、Toast提示、頁(yè)面布局、視頻播放。
2.然后在info.plist文件中添加相冊(cè)權(quán)限提示:

3.開始寫代碼,導(dǎo)入相應(yīng)頭文件和設(shè)置好相應(yīng)的協(xié)議還有數(shù)據(jù)
#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;? ? ? ? ? ? //相冊(cè)瀑布流
? ? NSMutableArray*imageArray;? ? ? ? ? ? ? ? ? ? //圖片數(shù)組
? ? NSMutableArray*selectArray;? ? ? ? ? ? ? ? ? ? //圖片選擇數(shù)組
? ? NSMutableArray*phArray;? ? ? ? ? ? ? ? ? ? ? ? //媒體數(shù)據(jù)數(shù)組
? ? NSIntegernums;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //最大可選擇的照片數(shù)量
? ? NSInteger? IorV;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //視頻還是照片 -1:未選擇? 0:照片? 1:視頻
? ? UIView*bottomV;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //相冊(cè)所在的父視圖
? ? UIView*toolView;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //相冊(cè)上方的工具視圖(可自定義)
? ? UISwipeGestureRecognizer* recognizerUp;? ? ? ? //上滑手勢(shì)
? ? UISwipeGestureRecognizer* recognizerDown;? ? ? //下拉手勢(shì)
? ? BOOLisTop;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //是否滑動(dòng)到頂部
? ? BOOLUPorDown;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //是否是在全屏狀態(tài)
? ? NSIntegerpage;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //頁(yè)碼
? ? BOOLready;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //是否準(zhǔn)備好再次刷新
}
@property(nonatomic,strong) UIImagePickerController *imagePicker;
@end
4.開始進(jìn)入時(shí)候檢查權(quán)限
-(void)checkPermissions
{
? ? [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
? ? ? ? if (status == PHAuthorizationStatusAuthorized) {
? ? ? ? ? ? dispatch_main_async_safe(^{
? ? ? ? ? ? ? ? [selfloadImageArray];
? ? ? ? ? ? });
? ? ? ? }else{
? ? ? ? ? ? //未獲取相冊(cè)權(quán)限
? ? ? ? ? ? [self showAlrtToSetting];
? ? ? ? }
? ? }];
}
/**
?檢測(cè)到未開啟相冊(cè)權(quán)限之后的提醒
?*/
-(void) showAlrtToSetting
{
? ? UIAlertController* alert = [UIAlertControlleralertControllerWithTitle:@"開啟相冊(cè)權(quán)限"message:@"打開相冊(cè)權(quán)限,上傳您喜歡的圖片"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);
? ? }];
? ? //創(chuàng)建一個(gè)layout布局類
? ? UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc]init];
? ? //設(shè)置布局方向?yàn)榇怪绷鞑季?/i>
? ? layout.scrollDirection = UICollectionViewScrollDirectionVertical;
? ? //設(shè)置每個(gè)item的大小為100*100
? ? layout.itemSize=CGSizeMake(WIDTH/4-1,WIDTH/4-1);
? ? //創(chuàng)建collectionView 通過一個(gè)布局策略layout來創(chuàng)建
? ? 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];
? ? //注冊(cè)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.加載本地照片和視頻數(shù)據(jù)
-(void)loadImageArray
{
? ? [self.view makeToastActivity:CENTER];
? ? dispatch_async(dispatch_get_global_queue(0, 0), ^{
? ? ? ? // 處理耗時(shí)操作的代碼塊
? ? ? ? phArray= [NSMutableArrayarray];
? ? ? ? imageArray= [NSMutableArrayarray];
? ? ? ? PHFetchOptions *options = [[PHFetchOptions alloc] init];
? ? ? ? options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
? ? ? ? PHFetchResult*assetsFetchResults = [PHAssetfetchAssetsWithOptions:options];
? ? ? ? for(PHAsset*assetinassetsFetchResults)
? ? ? ? {
? ? ? ? ? ? //判斷本地媒體數(shù)據(jù)是照片類型和視頻類型,就加入到phArray數(shù)組中
? ? ? ? ? ? if (asset.mediaType == PHAssetMediaTypeImage || asset.mediaType == PHAssetMediaTypeVideo)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? [phArrayaddObject:asset];
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? phArray=(NSMutableArray *)[[phArray reverseObjectEnumerator] allObjects];? //數(shù)組倒序排列
? ? ? ? //加載前兩百條數(shù)據(jù)(防止加載耗時(shí)過長(zhǎng))
? ? ? ? NSIntegercounts =phArray.count;
? ? ? ? if(counts>200)
? ? ? ? {
? ? ? ? ? ? counts =200;
? ? ? ? }
? ? ? ? for(inti=0;i
? ? ? ? {
? ? ? ? ? ? PHAsset*asset = [phArrayobjectAtIndex:i];
? ? ? ? ? ? PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
? ? ? ? ? ? /** resizeMode:對(duì)請(qǐng)求的圖像怎樣縮放。有三種選擇:None,默認(rèn)加載方式;Fast,盡快地提供接近或稍微大于要求的尺寸;Exact,精準(zhǔn)提供要求的尺寸。 deliveryMode:圖像質(zhì)量。有三種值:Opportunistic,在速度與質(zhì)量中均衡;HighQualityFormat,不管花費(fèi)多長(zhǎng)時(shí)間,提供高質(zhì)量圖像;FastFormat,以最快速度提供好的質(zhì)量。
?? ? ? ? ? ? 這個(gè)屬性只有在 synchronous 為 true 時(shí)有效。
?? ? ? ? ? ? */
? ? ? ? ? ? option.resizeMode = PHImageRequestOptionsResizeModeFast;//控制照片尺寸
? ? ? ? ? ? option.deliveryMode=1;//控制照片質(zhì)量
? ? ? ? ? ? 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];
? ? ? ? ? ? }];
? ? ? ? }
? ? ? ? //初始化是否選擇的數(shù)組
? ? ? ? selectArray= [NSMutableArrayarray];
? ? ? ? for(inti=0;i
? ? ? ? {
? ? ? ? ? ? [selectArrayaddObject:@"0"];
? ? ? ? }
? ? ? ? //通知主線程刷新
? ? ? ? dispatch_async(dispatch_get_main_queue(), ^{
? ? ? ? ? ? //回調(diào)或者說是通知主線程刷新
? ? ? ? ? ? [myCollectionViewreloadData];
? ? ? ? ? ? [self.viewhideToastActivity];
? ? ? ? });
? ? });
}
7.上滑和下拉操作手勢(shì)實(shí)現(xiàn)方法
- (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.下拉加載下一頁(yè)(200條)的數(shù)據(jù)
-(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), ^{
? ? ? ? // 處理耗時(shí)操作的代碼塊
? ? ? ? for(NSIntegeri=nowCounts;i
? ? ? ? {
? ? ? ? ? ? PHAsset*asset = [phArrayobjectAtIndex:i];
? ? ? ? ? ? PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
? ? ? ? ? ? /** resizeMode:對(duì)請(qǐng)求的圖像怎樣縮放。有三種選擇:None,默認(rèn)加載方式;Fast,盡快地提供接近或稍微大于要求的尺寸;Exact,精準(zhǔn)提供要求的尺寸。 deliveryMode:圖像質(zhì)量。有三種值:Opportunistic,在速度與質(zhì)量中均衡;HighQualityFormat,不管花費(fèi)多長(zhǎng)時(shí)間,提供高質(zhì)量圖像;FastFormat,以最快速度提供好的質(zhì)量。
?? ? ? ? ? ? 這個(gè)屬性只有在 synchronous 為 true 時(shí)有效。
?? ? ? ? ? ? */
? ? ? ? ? ? option.resizeMode = PHImageRequestOptionsResizeModeFast;//控制照片尺寸
? ? ? ? ? ? option.deliveryMode=1;//控制照片質(zhì)量
? ? ? ? ? ? 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(), ^{
? ? ? ? ? ? //回調(diào)或者說是通知主線程刷新
? ? ? ? ? ? [myCollectionViewreloadData];
? ? ? ? ? ? [self.viewhideToastActivity];
? ? ? ? ? ? page++;
? ? ? ? ? ? ready=YES;
? ? ? ? });
? ? });
}
9.手勢(shì)協(xié)議的實(shí)現(xiàn)(防止UICollectionView的滾動(dòng)事件和手勢(shì)沖突)
- (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.滾動(dòng)過程中的監(jiān)聽
- (void)scrollViewDidScroll:(UIScrollView*)scrollView
{
? ? CGPointlocalPoint = scrollView.contentOffset;
? ? if(localPoint.y<=0)
? ? {
? ? ? ? isTop=YES;
? ? }
? ? else
? ? {
? ? ? ? isTop=NO;
? ? ? ? if(localPoint.y>(page+1)*3800)? //還未到達(dá)最底部就開始加載下200條,預(yù)防卡頓
? ? ? ? {
? ? ? ? ? ? if(ready)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? [selffooterClick];
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
11.CollectionView協(xié)議方法實(shí)現(xiàn)
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)collectionView
{
? ? return1;
}
/**
?設(shè)置CollectionView每組所包含的個(gè)數(shù)
?*/
- (NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section
{
? ? return imageArray.count;
}
/**
?設(shè)置CollectionCell的內(nèi)容
?*/
- (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"])? //照片類型,隱藏視頻相關(guān)控件
? ? {
? ? ? ? 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"])
? ? ? ? {? //異步獲取視頻時(shí)長(zhǎng)
? ? ? ? ? ? dispatch_async(dispatch_get_global_queue(0,0), ^{
? ? ? ? ? ? ? ? // 處理耗時(shí)操作的代碼塊...
? ? ? ? ? ? ? ? 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;
}
/**
?定義每個(gè)UICollectionView的大小
?*/
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath
{
? ? return? CGSizeMake(WIDTH/4-1,WIDTH/4-1);
}
/**
?定義整個(gè)CollectionViewCell與整個(gè)View的間距
?*/
- (UIEdgeInsets)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
? ? return UIEdgeInsetsMake(1, 1, 1, 1);//(上、左、下、右)
}
/**
?定義每個(gè)UICollectionView的橫向間距
?*/
- (CGFloat)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
? ? return0;
}
/**
?定義每個(gè)UICollectionView的縱向間距
?*/
- (CGFloat)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
? ? return0;
}
/**
?點(diǎn)擊CollectionView觸發(fā)事件
?*/
-(void)collectionView:(UICollectionView*)collectionView didSelectItemAtIndexPath:(NSIndexPath*)indexPath
{
? ? if([[imageArray[indexPath.row]objectForKey:@"type"]isEqualToString:@"0"])//照片
? ? {
? ? ? ? [selflookImage:indexPath.row];
? ? }
? ? else
? ? {
? ? ? ? [selflookVideo:indexPath.row];
? ? }
}
/**
?設(shè)置CollectionViewCell是否可以被點(diǎn)擊
?*/
- (BOOL)collectionView:(UICollectionView*)collectionView shouldSelectItemAtIndexPath:(NSIndexPath*)indexPath
{
? ? return YES;
}
12.時(shí)間格式處理
-(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.查看視頻(單獨(dú)寫了一個(gè)查看視頻文件,詳情請(qǐng)看下方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.選擇視頻或照片實(shí)現(xiàn)
-(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)//是最后一個(gè)只要刷新最后一條的數(shù)據(jù)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? [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個(gè)視頻!"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 代理實(shí)現(xiàn)賦值數(shù)據(jù)(圖片查看)
- (NSUInteger)yb_numberOfCellForImageBrowserView:(YBImageBrowserView*)imageBrowserView {
? ? returnphArray.count;
}
- (id)yb_imageBrowserView:(YBImageBrowserView*)imageBrowserView dataForCellAtIndex:(NSUInteger)index {
? ? YBImageBrowseCellData *data = [YBImageBrowseCellData new];
? ? data.phAsset=phArray[index];
? ? returndata;
}
備注:目前根據(jù)項(xiàng)目,最多只能選擇9張圖片,并且圖片和視頻只能選擇一種,所以做了限制。選擇完成后,循環(huán)遍歷selectArray既可獲得所選的文件數(shù)據(jù),代碼大致如下:
{
? ? imageUrlArray = [NSMutableArray array];
? ? NSMutableArray *postImgArray = [NSMutableArray array];
? ? for(inti=0;i
? ? {
? ? ? ? if(![selectArray[i] isEqualToString:@"0"])
? ? ? ? {
? ? ? ? ? ? PHAsset *asset = phArray[i];
? ? ? ? ? ? if(IorV==1)? //視頻
? ? ? ? ? ? {
? ? ? ? ? ? ? ? //視頻只能選擇一個(gè),直接這里轉(zhuǎn)視頻,然后上傳
? ? ? ? ? ? ? ? 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(@"視頻時(shí)長(zhǎng):%d",seconds);
? ? ? ? ? ? ? ? ? ? ? ? NSData *data = [NSData dataWithContentsOfURL:urls];
? ? ? ? ? ? ? ? ? ? ? ? NSInteger videoSize = data.length/1024;
? ? ? ? ? ? ? ? ? ? ? ? floatsizes = (float)videoSize/1024;
? ? ? ? ? ? ? ? ? ? ? ? NSLog(@"視頻大?。?.2f M",sizes);
? ? ? ? ? ? ? ? ? ? ? ? /*
?? ? ? ? ? ? ? ? ? ? ? ? 創(chuàng)建AVAssetExportSession對(duì)象
?? ? ? ? ? ? ? ? ? ? ? ? 壓縮的質(zhì)量
?? ? ? ? ? ? ? ? ? ? ? ? AVAssetExportPresetLowQuality 最low的畫質(zhì)最好不要選擇實(shí)在是看不清楚
?? ? ? ? ? ? ? ? ? ? ? ? AVAssetExportPresetMediumQuality 使用到壓縮的話都說用這個(gè)
?? ? ? ? ? ? ? ? ? ? ? ? AVAssetExportPresetHighestQuality 最清晰的畫質(zhì)
?? ? ? ? ? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? ? ? ? ? ? AVAssetExportSession * session = [[AVAssetExportSession alloc] initWithAsset:avasset presetName:AVAssetExportPreset960x540];
? ? ? ? ? ? ? ? ? ? ? ? //優(yōu)化網(wǎng)絡(luò)
? ? ? ? ? ? ? ? ? ? ? ? session.shouldOptimizeForNetworkUse =YES;
? ? ? ? ? ? ? ? ? ? ? ? //轉(zhuǎn)換后的格式
? ? ? ? ? ? ? ? ? ? ? ? //拼接輸出文件路徑 為了防止同名 可以根據(jù)日期拼接名字 或者對(duì)名字進(jìn)行MD5加密
? ? ? ? ? ? ? ? ? ? ? ? NSString* path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES) lastObject] stringByAppendingPathComponent:@"hello.mp4"];
? ? ? ? ? ? ? ? ? ? ? ? //判斷文件是否存在,如果已經(jīng)存在刪除
? ? ? ? ? ? ? ? ? ? ? ? [[NSFileManager defaultManager]removeItemAtPath:path error:nil];
? ? ? ? ? ? ? ? ? ? ? ? //設(shè)置輸出路徑
? ? ? ? ? ? ? ? ? ? ? ? session.outputURL = [NSURL fileURLWithPath:path];
? ? ? ? ? ? ? ? ? ? ? ? //設(shè)置輸出類型 這里可以更改輸出的類型 具體可以看文檔描述
? ? ? ? ? ? ? ? ? ? ? ? session.outputFileType = AVFileTypeMPEG4;
? ? ? ? ? ? ? ? ? ? ? ? session.videoComposition = [selfgetVideoComposition:urlAsset];
? ? ? ? ? ? ? ? ? ? ? ? [session exportAsynchronouslyWithCompletionHandler:^{
? ? ? ? ? ? ? ? ? ? ? ? ? ? //壓縮完成
? ? ? ? ? ? ? ? ? ? ? ? ? ? if(session.status==AVAssetExportSessionStatusCompleted) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //在主線程中刷新UI界面,彈出控制器通知用戶壓縮完成
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dispatch_async(dispatch_get_main_queue(), ^{
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? NSLog(@"導(dǎo)出完成");
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 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
? ? ? ? ? ? {
? ? ? ? ? ? ? ? //照片可以傳多張,所以循環(huán)添加進(jìn)postImgArray
? ? ? ? ? ? ? ? PHImageManager *manager = [PHImageManager defaultManager];
? ? ? ? ? ? ? ? PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
? ? ? ? ? ? ? ? /** resizeMode:對(duì)請(qǐng)求的圖像怎樣縮放。有三種選擇:None,默認(rèn)加載方式;Fast,盡快地提供接近或稍微大于要求的尺寸;Exact,精準(zhǔn)提供要求的尺寸。 deliveryMode:圖像質(zhì)量。有三種值:Opportunistic,在速度與質(zhì)量中均衡;HighQualityFormat,不管花費(fèi)多長(zhǎng)時(shí)間,提供高質(zhì)量圖像;FastFormat,以最快速度提供好的質(zhì)量。
?? ? ? ? ? ? ? ? 這個(gè)屬性只有在 synchronous 為 true 時(shí)有效。
?? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? ? option.resizeMode = PHImageRequestOptionsResizeModeFast;//控制照片尺寸
? ? ? ? ? ? ? ? option.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;//控制照片質(zhì)量
? ? ? ? ? ? ? ? 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)
?? ? ? ? ? ? ? ? ? ? {
?? ? ? ? ? ? ? ? ? ? ? ? //當(dāng)postImgArray的數(shù)量和開始記錄的選中數(shù)量相等的時(shí)候,開始上傳操作
?? ? ? ? ? ? ? ? ? ? }
?? ? ? ? ? ? ? ? }];
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
大致思路是如此,第一次寫簡(jiǎn)書,比較亂,大家勿怪,下方貼上github鏈接,可以下載下來看demo參考,順便給個(gè)star,感謝??。祝大家生活愉快,永不脫發(fā)。