1. 参考资料:
感谢!感谢!感谢! 重三~
- 学习请点下面链接:
iOS 开发之照片框架详解之二 —— PhotoKit 详解(上)
iOS 开发之照片框架详解之二 —— PhotoKit 详解(下) - 获取相册资源的工具请下载:
里面提供了数据的处理类,以及选取photo UI的封装。自定义扩展性强。
去下载demo
2. 数据处理思路
- 每次都是从外向内分析,这次从底层向上分析
获取相册 -> 获取相册中的资源 -> 获取资源中的(图片或者视频) - 主要是对数据的处理,把UI分离出来,让你方便的获取相册资源,以及管理被选中的资源
- 预览图,宽度最大为 500像素。(建议400)
- 封装后,你所有的数据,都可以通过PYAblum 单例拿到
- 最后,需要在获取相册资源模块使用完成后,清空缓存
- (void)removeCache;
1. 获取相册
主要方法
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
- 根据类型 获取相册:
自定义一个枚举,实现自定义获取相册类型
///选取相册类型
typedef NS_ENUM(NSUInteger, Enum_PYAblumManager_AblumType){
///所有相册
Enum_Ablum_AblumAll = 1 << 0,
///PHAssetCollectionSubtypeAlbumRegular = 2, // 在 相册 应用中创建的相簿
Enum_Ablum_smartAlbums = 1 << 2,
///获取所有用户创建的相册 PHAssetCollectionSubtypeAlbumRegular
Enum_Ablum_topLevelUserCollections = 1 << 3,
/// PHAssetCollectionSubtypeAlbumSyncedAlbum = 5, // 从iPhone中同步到设备的相簿
Enum_Ablum_syncedAlbums = 1 << 4,
///PHAssetCollectionSubtypeAlbumMyPhotoStream = 100, // 用户自己的iCloud照片流
Enum_Ablum_myPhotoStreamAlbum = 1 << 5,
///PHAssetCollectionSubtypeAlbumCloudShared = 101, // 一个iCloud共享照片流
Enum_Ablum_sharedAlbums = 1 << 6,
};
- 根据枚举来获取相册列表
- ( NSArray *>*)getFetchResultAblumType: (Enum_PYAblumManager_AblumType)ablumType {
NSMutableArray * fetchResultArrayM = [[NSMutableArray alloc]init];
ablumType = [self ablumType:ablumType];
// 用户自己的iCloud照片流
if ((ablumType & Enum_Ablum_myPhotoStreamAlbum) == Enum_Ablum_myPhotoStreamAlbum) {
PHFetchResult *myPhotoStreamAlbum = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumMyPhotoStream options:nil];
[fetchResultArrayM addObject:myPhotoStreamAlbum];
}
// 在 相册 应用中创建的相簿
if((ablumType & Enum_Ablum_smartAlbums) == Enum_Ablum_smartAlbums) {
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
[fetchResultArrayM addObject:smartAlbums];
}
// 获取所有用户创建的相册
if((ablumType & Enum_Ablum_topLevelUserCollections) == Enum_Ablum_topLevelUserCollections) {
PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
[fetchResultArrayM addObject:topLevelUserCollections];
}
/// 从iPhone中同步到设备的相簿
if ((ablumType & Enum_Ablum_syncedAlbums) == Enum_Ablum_syncedAlbums) {
PHFetchResult *syncedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumSyncedAlbum options:nil];
[fetchResultArrayM addObject:syncedAlbums];
}
///
if ((ablumType & Enum_Ablum_sharedAlbums) == Enum_Ablum_syncedAlbums) {
PHFetchResult *sharedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumCloudShared options:nil];
[fetchResultArrayM addObject:sharedAlbums];
}
return fetchResultArrayM.copy;
}
- 把
PHFetchResult
变为相册model*
这里的model,类型不能写死,需要提供接口,才能得到最大扩展性。
传入自定义model的class,不过,自定义model必须继承自PYAblumModel
/// 返回相册
- (PYAblumModel *)getFetchResultWithAssetType: (Enum_PYAblumManager_AssetType)assetType andAblumType: (Enum_PYAblumManager_AblumType) ablumType allBlum:(void(^)(NSArray * blumArray))allBlumBlock {
NSSortDescriptor *sortDescriptor = nil;
PHFetchOptions *options = [[PHFetchOptions alloc]init];
///是否按时间排序
if (self.isTimeRank) {
sortDescriptor = [[NSSortDescriptor alloc]initWithKey:@"creationDate" ascending:false];
options.sortDescriptors = @[sortDescriptor];
}
/// handle assetType
options = [self setOptions:options WithAssetType:assetType];
///获取 fetchResult
NSArray * fetchResultArray = [self getFetchResultAblumType:ablumType];
NSMutableArray * fetchResultArrayM = [NSMutableArray new];
for (PHFetchResult *fetchResult in fetchResultArray) {
for (PHAssetCollection *collection in fetchResult) {
// 有可能是PHCollectionList类的的对象,过滤掉
if (![collection isKindOfClass:[PHAssetCollection class]]) continue;
PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:options];
if (fetchResult.count < 1) continue;
if ([collection.localizedTitle containsString:@"Deleted"] || [collection.localizedTitle isEqualToString:@"最近删除"]) continue;
if (!self.ablumModelClass) {
self.ablumModelClass = PYAblumModel.class;
NSLog(@"self.ablumClass, 没有设置值,自动设置为 PYAblumModel");
}
PYAblumModel *model = (PYAblumModel *)[self.ablumModelClass new];
model.name = collection.localizedTitle;
model.assetfetchResult = fetchResult;
//设置封面
if ([self isCameraRollAlbum:collection.localizedTitle]) {
[fetchResultArrayM insertObject:model atIndex:0];
} else {
[fetchResultArrayM addObject:model];
}
}
}
NSArray *bulmArray = fetchResultArrayM.copy;
if (allBlumBlock) allBlumBlock(bulmArray);
return bulmArray.firstObject;
}
- 来看一下PYAblumManager.h
这里提供了一些自定义接口
@interface PYAblumManager : NSObject
/// 是否按照时间对资源排序(默认为true)
@property (nonatomic,assign) BOOL isTimeRank;
/// 相册的 model class 一定要继承自(PYAblumManagerModel)
@property (nonatomic,strong) Class ablumModelClass;
/// 返回传入的modelClass对象 主相册, block里面为相册数组
- (PYAblumModel *)getFetchResultWithAssetType: (Enum_PYAblumManager_AssetType)assetType andAblumType: (Enum_PYAblumManager_AblumType) ablumType allBlum:(void(^)(NSArray * blumArray))allBlumBlock;
@end
- PYAblumModel.h
在model中你可以拿到 封面 + name + 相册的资源集合
@interface PYAblumModel : NSObject
/// 封面
@property (nonatomic,strong) UIImage *coverImageView;
@property (nonatomic,copy) NSString *name;
@property (nonatomic,strong) PHFetchResult *assetfetchResult;
@end
2. 获取资源
- 主要是 对资源进行筛选,大小,时长等限制,并生成PYAssetModel数组
- 对选择的资源进行了处理,记录了选中状态以及选中顺序。
- 对model 的自定义。一定要继承自PYAssetModel
///资源管理者, 获取 相册中的资源
@interface PYAssetManager : NSObject
//MARK: - 筛选
///最小的 图片的size 默认 为 (0,0)
@property (nonatomic,assign) CGSize minSize;
///最大的 图片的size 默认 为(80,80)
@property (nonatomic,assign) CGSize maxSize;
///最短时长 默认为 0
@property (nonatomic,assign) CGFloat minTime;
///最长时长 默认为 1小时
@property (nonatomic,assign) CGFloat maxTime;
///资源类型 type
@property (nonatomic,assign) Enum_PYAblumManager_AssetType type;
///MARK: - 要继承自 PYAssetModel,
///默认 PYAssetModel
@property (nonatomic,strong) Class assetModelClass;
/**
管理选中的assetModel
@param clickedModel 被点击的model
@param beOperatedArray 被操作的数组(请穿一个生命周期适当的数组)
@param maxCount 最大可选中数量 (小于0 则为无最大选中限制)
@param block 超出最大数量的回调
@return 返回被操作后的数组
*/
+ (NSMutableArray *)getSelectAssetArrayWithClickedModel: (PYAssetModel *)clickedModel andBeOperated: (NSMutableArray *) beOperatedArray andMaxCount:(NSInteger) maxCount andOverTopBlock: (void(^)(NSArray *modelArray, BOOL isVoerTop))block;
///解析 asset
- (NSArray *)getAssetWithFetchResult:(PHFetchResult*)fetchResult;
@end
model中暴露的接口
@interface PYAssetModel : NSObject
///资源
@property (nonatomic,strong) PHAsset *asset;
///创建的时间
@property (nonatomic,strong) NSDate *creationDate;
///创建时间
@property (nonatomic,assign) NSInteger createTimeInteger;
///资源的类型
@property (nonatomic,assign) Enum_PYAblumManager_AssetType assetType;
/// 是否选中状态
@property (nonatomic,assign) BOOL isSelected;
/// 选中状态下 第几个被选中的 (没有选中状态下默认为 小于0)
@property (nonatomic,assign) NSInteger orderNumber;
/// 当前选中的model 是否超出最大值了;
@property (nonatomic,assign) BOOL isBeyondTheMaximum;
///image ID
@property (nonatomic,assign) PHImageRequestID imageRequestID;
///缩略图
@property (nonatomic,strong) UIImage *degradedImage;
///精致的缩略图
@property (nonatomic,strong) UIImage *delicateImage;
///原图
@property (nonatomic,strong) UIImage *originImage;
@end
3. 获取图片
- 分为缩略图,精致的压缩图,原图
- 主要是对PHAsset 进行了解析
///是否需自动调整图片方向 默认为true
@property (nonatomic,assign) BOOL shouldFixOrientation;
///获取封面照片
- (PHImageRequestID) getPotoWithAlbum: (PHFetchResult *)assetfetchResult
andPotoWidth: (CGFloat)Width
andSortAscendingByDate: (BOOL)isSortAscendingByDate
andCompletion:(void (^)(UIImage *))completion;
/// 获取原图
- (PHImageRequestID) getOriginPoto:(PHAsset *)asset andCompletion: (void (^)(UIImage *))completion;
/**
获取图片,默认获取的是缩略图,如果networkAccessAllowed 为true,则第二次调用block为获取到的原图
@param asset 资源
@param width 照片 期望宽度
@param completion 图片加载完成的block 如果info[PHImageResultIsDegradedKey] 为 YES,则表明当前返回的是缩略图,否则是原图。
@param progressBlock 进度相关
@param networkAccessAllowed 参数控制是否允许 icloud 网络请求,默认为 NO,
@return 返回了 PHImageRequestID
*/
- (PHImageRequestID) getPotoWithAsset: (PHAsset *)asset
andSetPotoWidth: (CGFloat)width
andnetworkAccessAllowed: (BOOL) networkAccessAllowed
andCompletion: (void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion
andProgress:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressBlock;
@end
4. 接口汇总,所有的数据处理 都要通过单例PYAblum操作
///提供了一些常用方法,可以用单例中的manager 来做一些其他操作
@interface PYAblum : NSObject
#pragma mark - 单例
///swift 请调用这方法,获取
+ (PYAblum *) defaultAblum;
+ (PYAblum *) ablum;
/// “所有照片” 相册中,预先加载的个数
@property (nonatomic,assign) NSInteger allPhotoAbulmPreloadingCount;
#pragma mark - 关于相册
///相册管理类
@property (nonatomic,strong) PYAblumManager *ablumManager;
///自定义返回的model : 一定要继承自(PYAblumManagerModel)
@property (nonatomic,strong) Class ablumModelClass;
#pragma mark - 关于资源的
///资源管理者
@property (nonatomic,strong) PYAssetManager *assetManager;
///缓存的所有资源
@property (nonatomic,strong,readonly) NSArray *cacheAssetModelArray;
///所有相片相册中 转化后的资源model
@property (nonatomic,strong,readonly) NSArray *allPhotoAblumModelArray;
///缓存的所有照片
@property (nonatomic,strong,readonly) NSArray * allPhotoAblumImageArray;
///自定义返回的model : 默认 PYAssetModel, 一定要继承自(assetModel)
@property (nonatomic,strong) Class assetModelClass;
//MARK: 关于选择资源的方法
/**
管理选中的assetModel
*
@param clickedModel 被点击的model
@param maxCount 最大可选中数量 (小于0 则为无最大选中限制)
@param block 超出最大数量的回调
@return 返回被操作后的数组
*/
+ (NSMutableArray *)getSelectAssetArrayWithClickedModel: (PYAssetModel *)clickedModel andMaxCount:(NSInteger) maxCount andOverTopBlock: (void(^)(NSArray *modelArray, BOOL isVoerTop))block;
/// 选被中的assetModel
@property (nonatomic,strong) NSMutableArray *selectedAssetModelArray;
/// 消除选中其中的某个asset
- (void)removeSelectedAssetWith:(PYAssetModel *)asset;
/// 清理 selectedAssetModelArray
- (void)removeSelectedAssetModelArray;
#pragma mark - image 管理类
@property (nonatomic,strong) PYImageManager *imageManager;
#pragma mark - 常用 方法
/**
获取相册中的图片,其中不包含 视频的内容
@param w image 的大小(assetLastModelBlock 调用中 image的大小)
@param assetFirstModelBlock 缩略图
@param assetLastModelBlock 精致些的图片
*/
- (void) getAblumAllImageWithWidth: (CGFloat)w andBlock: (void(^)(NSArray *assetFirstModelArray, NSArray *degradedArray)) assetFirstModelBlock andBlock: (void(^)(NSArray *assetLastModelArray, NSArray *originArray)) assetLastModelBlock;
/**
* 获取所有相册 并获取相册的封面
@param getAblumblock 获取相册
@param w image的宽度,高度会自动比例计算
* ablumModel 默认为 PYAblumModel, 如果,自定义,请给self.ablumModelClass赋值
*/
- (void) getAbulmSetCoverImageWithImageWidth: (CGFloat)w andBlock: (void(^)(NSArray *ablumModel))getAblumblock;
/**
获取资源数组中的某张图片
* 默认做了缓存,(index先从缓存中获取,再网络获取)
@param assetArray 资源集合
@param index 要获取的资源的下标
@param width image 的宽度,如果width <= 0 或者 width 大于 image原有宽度,则返回原图
*/
- (void) getPhotoWithAssetArray: (NSArray *)assetArray andIndex: (NSInteger) index andImageSize: (CGFloat)width andCallBack: (void(^)(UIImage *))callBack;
/**
获取资源数组中的某张图片
* 默认做了缓存,(index先从缓存中获取,再网络获取)
@param assetArray 资源集合
@param index 要获取的资源的下标
@param width image 的宽度,如果width <= 0 或者 width 大于 image原有宽度,则返回原图
*/
- (void) getPhotoWithAssetModelArray: (NSArray *)assetArray andIndex: (NSInteger) index andImageSize: (CGFloat)width andCallBack: (void(^)(PYAssetModel *))callBack;
/**
时间排序
@param modelArray model array
@param isASC 是否升序,(最近期 照片 在后面)
*/
- (NSArray *) sortWithModelArray: (NSArray *)modelArray andIsASC: (BOOL)isASC ;
///删除 缓存的缩略图 及预览图
- (void)removeCache;
@end
3. UI处理
1. 图片的选择
有了数据,那么UI就好说了,对collectionView的封装就看demo吧
点我下载demo