使用PhotoKit 搭建相册选择器(支持多选)

1. 闲谈

iOS8 以后苹果推出新的关于相册的框架-PhotoKit,相比较之前的AssetsLibrary 框架有了很大的提升,由于初次接触这个新的框架,也在网上查找了很多大神的博客资料,本文就浅谈一下自己对这个框架的理解。

2.介绍

PhotoKit 主要有PHAssetPHFetchOptionsPHFetchResultPHAssetCollectionPHImageManagerPHCollectionList几个重要的类。

PHAsset:代表照片库的一个资源 也就是具体的某一个照片或者视频。

PHFetchOptions: 获取资源的参数 可以为nil

PHFetchResult:表示一系列的资源结果集合,也可以是相册的集合 从PHCollection的方法中获得.

PHAssetCollection: PHCollection的子类,表示一个相册或者一个时刻(最近删除、收藏)

PHImageManager:用于处理资源的加载,加载图片的过程有缓存,可以使用 PHImageRequestOptions控制资源的输出尺寸等规格

PHCollectionList:表示一组PHCollection

3.开始搭建

  • 3.1 由于从相册获取照片之后需要展示,所有首先我们需要创建一个展示你选中照片的界面,因此我使用的是UICollectionView布局界面,并自定义了一个UICollectionViewCell 可以实现删除照片 命名为 - PhotoCell,如下所示:
#import <UIKit/UIKit.h>
#import <Photos/Photos.h>
@class PhotoCell;
@protocol PhotoCellDelegate <NSObject>
/**删除照片的代理方法*/
-(void)deleteThePhotoForCell:(PhotoCell *)cell  deleteBtn:(UIButton *)btn;
@end

@interface PhotoCell : UICollectionViewCell
/**图片视图*/
@property(nonatomic,strong)UIImageView *photoView;
/**删除按钮*/
@property(nonatomic,strong)UIButton *deleteBTn;
/**代理*/
@property(nonatomic,weak) id <PhotoCellDelegate> delegate;
@end
  • 3.2 创建一个管理获取相册资源的工具类 - YHPhotosData,使用这个工具类实现以下功能:获取所有相册列表、获取某一个相册中的照片资源、 将具体某一个照片资源转化为照片。
    YHPhotosData.h文件中
#import <Foundation/Foundation.h>
#import <Photos/Photos.h>//系统照片的框架
@interface YHPhotosData : NSObject
//获取所有的相册集
+(NSMutableArray *)getAllPhotoListData;
//获取某一个相册的所有资源
+(NSMutableArray *)getPhotosForPHAssetCollection:(PHAssetCollection *)collection;
//从相册的某一个照片资源获取一张高清照片
-(void)getImageObject:(id)set Complection:(void(^)(UIImage *photo,BOOL isDegraded))complection;
@end

YHPhotosData.m文件中

+(NSMutableArray *)getAllPhotoListData{
   NSMutableArray *dataArray = [NSMutableArray array];
   //1.0列出所有智能相册
   PHFetchResult *samrtResult  = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
 for(int i = 0 ;i<samrtResult.count; i++) {  
       [dataArray addObject:samrtResult[i]];
   }
  //2.0列出所有的用户创建的相册
   PHFetchResult *userResult = [PHAssetCollection fetchTopLevelUserCollectionsWithOptions:nil]; 
   for (PHAssetCollection *sub  in userResult) {
       [dataArray addObject:sub];
   } 
 return dataArray;
}
+(NSMutableArray *)getPhotosForPHAssetCollection:(PHAssetCollection *)collection{
    NSMutableArray *photosArray = [NSMutableArray array];
    //1.获取了结果集
    PHFetchResult *photosResult = [PHAsset fetchAssetsInAssetCollection:collection options:nil];  
    //2.便利结果集 取出具体某一张图片资源  添加在数组中  
    for(PHAsset *set  in  photosResult){
        if(set.mediaSubtypes == PHAssetMediaSubtypeNone){   
            [photosArray addObject:set];
        }    
    }
    return  photosArray;
}
-(void)getImageObject:(id)set Complection:(void (^)(UIImage *, BOOL))complection
{
    if ([set isEqual:[PHAsset class]]){     
        PHAsset *photoSet = set;
        CGFloat mainWidth = [UIScreen mainScreen].bounds.size.width;
       //1.0算出照片资源自身的比例
        CGFloat setScale = photoSet.pixelWidth/photoSet.pixelHeight;
        //1.1 获取屏幕比例
        //屏幕分辨率 scale = 1 代表 分辨率是320 * 480; =2 代表 分辨率是 640 * 960; = 3 代表 分辨率是 1242 * 2208
        CGFloat scale = [UIScreen mainScreen].scale;
        //1.2计算照片在不同屏幕上的像素   
        CGFloat pixWidth = mainWidth * scale;
        //1.3根据图片自身比例计算照片在屏幕上的高
        CGFloat pixheight = mainWidth/setScale;       
        /**
         *  PHImageManager 是通过请求的方式拉取图像,并可以控制请求得到的图像的尺寸、剪裁方式、质量,缓存以及请求本身的管理(发出请求、取消请求)等
         *
         *  @param pixelWidth 获取图片的宽
         *  @param pixelHeight 获取图片的高
         *  @param contentMode 图片的剪裁方式
         *
         *  @return
         */    
     [[PHImageManager defaultManager] requestImageForAsset:photoSet targetSize:CGSizeMake(pixWidth, pixheight) contentMode:PHImageContentModeAspectFit options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
         // 排除取消,错误,低清图三种情况,即已经获取到了高清图
         BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
         if (downloadFinined) {
             //回调
             if (complection){           
                 complection(result,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
             }
         }
     }]; 
 }
}
  • 3.3 工具类写完之后,接下来开始创建相册列表控制器 PhotosListVC 用来展示所有的相册列表,同时自定义Cell(我这里定义的是PhotoListCell)用来显示每个相册。cell中显示的照片就是该相册中所有照片中的最后一张。
    PhotoListCell 定义非常简单,我在这里就不过多叙述了.
/**图片视图*/
@property(nonatomic,strong)UIImageView *photoView;
/**标题*/
@property(nonatomic,strong)UILabel *title;

这里比较重要的一个方法就是 给cell设置默认数据。既相册的标题 以及显示的照片(最后一张).

///设置数据
-(void)getImageForAssetCollection:(PHAssetCollection *)coll{  
    //获取该相册最后一张照片资源
    PHAsset *set = [[YHPhotosData getPhotosForPHAssetCollection:coll] lastObject] ;   
    //转化为照片  并设置数据  (由于相册可能没有照片需要判断一下,给一张默认的照片)          
    [[PHImageManager defaultManager]requestImageForAsset:set targetSize:self.photoView.frame.size contentMode:PHImageContentModeAspectFit options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
        if (result == nil) {
            self.photoView.image = [UIImage imageNamed:@"no_data"];
        }else {       
            self.photoView.image = result;
        }
    }];
     self.title.text = coll.localizedTitle;
}
  • 3.4 创建展示相册所有照片的控制器PhotoShowVC,并自定义个Cell展示照片,这里我自己定义的是PhotosShowCell.
    PhotosShowCell.h
#import <UIKit/UIKit.h>
#import <Photos/Photos.h>
//获取点击的照片
typedef void (^PhotosShowCellBlock)(UIImage *image);
@interface PhotosShowCell : UICollectionViewCell
/**选择按钮*/
@property(nonatomic,strong)UIButton *selectBTn;
//获取点击的那个照片blcok
@property(nonatomic,copy)PhotosShowCellBlock cellBlock;
//设置数据
-(void)setPhotoForPHAsset:(PHAsset *)set;
@end

PhotosShowCell.m

//设置cell数据 传递过来的都是一张照片资源  不是照片 需要转化
-(void)setPhotoForPHAsset:(PHAsset *)set{
    [[PHImageManager defaultManager]requestImageForAsset:set targetSize:self.photoView.frame.size contentMode:PHImageContentModeAspectFit options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {  
        if (result) {      
            // 排除取消,错误,低清图三种情况,即已经获取到了高清图
            BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
            if (downloadFinined) {     
                self.photoView.image =result;   
                if (self.cellBlock) {
                  //获取点击的照片
                    self.cellBlock(result);
                }
            }          
        }else {
            self.photoView.image = [UIImage imageNamed:@"no_data"];
        }     
    }];
}

在控制器PhotoShowVC创建一个可变数组selectImageArray存放选中的所有照片,在cell的点击方法中 执行cell的block方法获取到点击的照片, 并存放到数组selectImageArray中,同时改变cell上按钮的状态。

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
    PhotosShowCell *cell  = (PhotosShowCell *)[collectionView cellForItemAtIndexPath:indexPath];
    if (cell.selectBTn.selected) {
        cell.selectBTn.selected = NO;  
        [cell.selectBTn setImage:[UIImage imageNamed:@"select_no"] forState:UIControlStateNormal];
        [self.selectImageArray removeObjectAtIndex:indexPath.row];
    }else {
        cell.selectBTn.selected = YES;
        [cell.selectBTn setImage:[UIImage imageNamed:@"select_yes"] forState:UIControlStateNormal];  
        [cell setPhotoForPHAsset:self.imageArray[indexPath.row]];
         cell.cellBlock = ^(UIImage *image) {
         [self.selectImageArray addObject:image];
        };   
    }
}

然后在控制器PhotoShowVC创建完成、预览按钮以及定义一个返回首页并传递照片到首页的Blcok ,当选择结束点击完成时候,执行Blcok 将选中的图片数组传递到首页。

-(void)clickBtn:(UIButton *)sender{
    if (self.selectImageArray.count > 0) {
        if (self.block) {   
           // [self.navigationController popViewControllerAnimated:YES];
            self.block(self.selectImageArray);
        }
    }else {
        NSLog(@"还没选择图片");
    }
}

预览界面就不在过多叙述了,非常简单,详情看Demo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容