1. 闲谈
iOS8 以后苹果推出新的关于相册的框架-PhotoKit,相比较之前的AssetsLibrary 框架有了很大的提升,由于初次接触这个新的框架,也在网上查找了很多大神的博客资料,本文就浅谈一下自己对这个框架的理解。
2.介绍
PhotoKit
主要有PHAsset
、PHFetchOptions
、PHFetchResult
、PHAssetCollection
、PHImageManager
、PHCollectionList
几个重要的类。
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。