iOS开发------简单实现图片多选功能(AssetsLibrary篇)
2016-04-20 14:58
741 查看
AssetsLibrary.framework是iOS7.0之前用来获取手机所有的媒体资源的一个静态库,在iOS8.0之后完全可以用Photo.framework来代替,但因为涉及到适配iOS7,所以这个库用的还是比较多的。
实际上,多选图片有很多很好用的第三方,但找到一个完全符合自己需求的第三方也不是那么容易,就算找到,如果不懂,也不是很好修改代码才对,所以了解一下这个库也是很有必要的,这里就记录一下过程中的认识与问题。
如果小伙伴有什么好玩的库,还请介绍一下,很希望能和喜欢钻研技术的你们一起交流。
下面的内容是边看开发文档边研究使用,按自己的理解所写,如果出现错误,也请告知一下
本文中的所有代码:https://github.com/YRunIntoLove/YAImagePickerView
- ALAssetsLibrary 是一个资源库,所有的资源组最初都是从这个类的对象中获得.
- ALAssetsGroup 是一个资源组,里面包含了每个资源组的基本信息以及包含的所有资源,可以通过设置过滤器属性来选择自己想要的资源类型.
- ALAssetsFilter 是一个过滤器,比如需要从资源组中遍历出所有的资源,视频资源还是图片资源.
- ALAsset 是一个资源对象,里面可以取到组的信息,详细信息可以通过获取自身的详细对象来获取
- ALAssetRepresentation 是资源对象的详细信息,ALAsset的详细内容都存在这个类中,比如高清图就存在该对象中。
这里加载所有的组,所以相机胶卷那个组位置不会是第一个,但是又想它在第一行,增加这个判断来保证存在相机胶卷,为其他操作进行准备:
2、在打开的组里面进行遍历并回调数据
用到的数据基本都谢了,至于View以及ViewController因为太长,就不在这里占地方了,如果有想法,可以下载代码研究一下。
最后还是要唠叨一句,不管是UIImageView还是UIButton,显示缩略图的时候不要忘记设置contentMode属性,这样才会出现选择展示图中的效果:
实际上,多选图片有很多很好用的第三方,但找到一个完全符合自己需求的第三方也不是那么容易,就算找到,如果不懂,也不是很好修改代码才对,所以了解一下这个库也是很有必要的,这里就记录一下过程中的认识与问题。
如果小伙伴有什么好玩的库,还请介绍一下,很希望能和喜欢钻研技术的你们一起交流。
下面的内容是边看开发文档边研究使用,按自己的理解所写,如果出现错误,也请告知一下
Thanks()
本文中的所有代码:https://github.com/YRunIntoLove/YAImagePickerView
类逻辑
研究一个库或者框架,总体逻辑一定是要缕清的,下面是个人的理解:- ALAssetsLibrary 是一个资源库,所有的资源组最初都是从这个类的对象中获得.
- ALAssetsGroup 是一个资源组,里面包含了每个资源组的基本信息以及包含的所有资源,可以通过设置过滤器属性来选择自己想要的资源类型.
- ALAssetsFilter 是一个过滤器,比如需要从资源组中遍历出所有的资源,视频资源还是图片资源.
- ALAsset 是一个资源对象,里面可以取到组的信息,详细信息可以通过获取自身的详细对象来获取
- ALAssetRepresentation 是资源对象的详细信息,ALAsset的详细内容都存在这个类中,比如高清图就存在该对象中。
类库中的类及其属性方法
这里提到的都是代码中用到的属性和方法,如果只是为了多图选择,那么以下的方法应该是够用的,不够的话可以Command+单击进入开发文档查看即可。
ALAssetsLibrary
资源库对象:/***相关类型***/ ALAssetsGroupLibrary //从iTunes 来的相册内容(如本身自带的向日葵照片) ALAssetsGroupAlbum //设备自身产生或从iTunes同步来的照片,但是不包括照片流跟分享流中的照片。(例如从各个软件中保存下来的图片) ALAssetsGroupEvent //相机接口事件产生的相册 ALAssetsGroupFaces //脸部相册(具体不清楚) ALAssetsGroupSavedPhotos //"相册胶卷"里面的照片 ALAssetsGroupPhotoStream //照片流 ALAssetsGroupAll //除了ALAssetsGroupLibrary上面所的内容
/*遍历相关类型的资源组*/ - (void)enumerateGroupsWithTypes:(ALAssetsGroupType)types usingBlock:(ALAssetsLibraryGroupsEnumerationResultsBlock)enumerationBlock failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock;
ALAssetsGroup
资源组对象:/***属性的key***/ extern NSString *const ALAssetsGroupPropertyName ; //组的标题 extern NSString *const ALAssetsGroupPropertyType; //组的类型 extern NSString *const ALAssetsGroupPropertyPersistentID ; //组的代表ID extern NSString *const ALAssetsGroupPropertyURL; //该组在本地存储的位置url
//获取相关属性的方法,property的值从上面的属性key中取即可 - (id)valueForProperty:(NSString *)property; //获取资源组的预览图 - (CGImageRef)posterImage; //设置过滤器 - (void)setAssetsFilter:(ALAssetsFilter *)filter; //当前组的资源数,如果设置了过滤对象,此数目就是过滤之后存储资源对象的个数 - (NSInteger)numberOfAssets;
/***遍历资源的方法***/ //遍历所有的资源 - (void)enumerateAssetsUsingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock; //根据类型遍历 - (void)enumerateAssetsWithOptions:(NSEnumerationOptions)option usingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock;
//类型 typedef NS_OPTIONS(NSUInteger, NSEnumerationOptions) { NSEnumerationConcurrent = (1UL << 0), //顺序(Default) NSEnumerationReverse = (1UL << 1), //逆序 };
ALAssetsFilter
资源过滤器://获得组中所有的照片资源 + (ALAssetsFilter *)allPhotos; //获得组中所有的视频资源 + (ALAssetsFilter *)allVideos; //获得组中所有的资源 + (ALAssetsFilter *)allAssets;
ALAsset
资源对象:/***相关属性的key***/ extern NSString *const ALAssetPropertyType; //资源对象的类型 extern NSString *const ALAssetPropertyLocation; //资源对象的位置描述 extern NSString *const ALAssetPropertyDuration; //资源对象的持续时间(用于video类型的资源对象) extern NSString *const ALAssetPropertyOrientation; //资源对象的方向,如:左转,右转.. extern NSString *const ALAssetPropertyDate; //资源对象的创建时间对象 extern NSString *const ALAssetPropertyRepresentations; //资源对象的可用详细对象数组 extern NSString *const ALAssetPropertyURLs; //资源对象的详细对象的URLs extern NSString *const ALAssetPropertyAssetURL; //资源对象的资源标识码 /***相关类型的key***/ extern NSString *const ALAssetTypePhoto; //图片类型 extern NSString *const ALAssetTypeVideo; //视频类型 extern NSString *const ALAssetTypeUnknown; //位置类型
//获取相关属性的方法,property的值从上面的属性key中取即可,与ALAssertGroup是一样的 - (id)valueForProperty:(NSString *)property //获取自身详细信息对象的一个便利方法 - (ALAssetRepresentation *)defaultRepresentation; //获取一个方形的缩略图,但是不建议用,真是太模糊了 - (CGImageRef)thumbnail; //获取一个按照比例缩放的缩略图,建议用这个,还是比较清晰的(Demo中的属性用的是这个属性) - (CGImageRef)aspectRatioThumbnail;
ALAssetRepresentation
资源详情对象://当前对象的方向 - (ALAssetOrientation)orientation; //获得缩放比例 - (float)scale;
//获得一个铺满屏幕的高清图(Demo中预览的高清图就是取得这个属性) - (CGImageRef)fullScreenImage; //如果使用这个属性,直接用此方法生成UIImage对象 UIImage * image = [UIImage imageWithCGImage:fullScreenImage];
//获得一个重新处理的铺满屏幕的高清图 - (CGImageRef)fullResolutionImage; //如果使用这个属性,需要用下面的方法生成UIImage对象,不然会出现展示方向等错误,比如图片显示会变成左转90度的 UIImage * image = [UIImage UIImage imageWithCGImage:fullResolutionImage scale:fullResolutionImage.scale orientation:fullResolutionImage.orientation];
Demo部分代码
配置文件_YEnumConfig
// // YEnumConfig.h // YChoosePicturesDemo // // Created by YueWen on 16/4/15. // Copyright © 2016年 YueWen. All rights reserved. // #ifndef YEnumConfig_h #define YEnumConfig_h @import UIKit; @import AssetsLibrary; #pragma mark - typedef enum : NSUInteger { YChoosePhotoSequenceTypeDefault = 0, //默认是按照选择的顺序 YChoosePhotoSequenceTypeDate //按照图片在相册的顺序 } YChoosePhotoSequenceType; #pragma mark - //照片选择的Block回调 typedef void(^ImagesBlock)(NSArray <UIImage *> *); #pragma mark - YPhotoManager typedef void(^ALAssetGroupBlock)(NSArray <ALAssetsGroup *> * groups); typedef void(^ALAssetPhotoBlock)(NSArray <ALAsset *> * photos); typedef void(^ALAssetFailBlock)(NSString * error); #pragma mark - YPhotoCollectionViewCell typedef void(^YPhotoCollectionViewBlock)(void); #endif /* YEnumConfig_h */
图片请求_YPhotoManager
按照习惯,还是创建了一个YPhotoManager的单例
@interface YPhotoManager () @property (nonatomic, strong) ALAssetsLibrary * library; //资源库 @property (nonatomic, copy) ALAssetGroupBlock block; //资源组进行的回调 @property (nonatomic, strong) NSMutableArray <ALAssetsGroup *> * groups; //存放所有照片组的数组对象 @property (nonatomic, strong) NSMutableArray <ALAsset *> * photos; //存放所有照片的数组对象 @end
创建单独的相册
/** * 创建组名叫做title的相片组 * * @param title 组名 */ - (void)createGroupWithTitle:(NSString *)title { //开始创建 [self.library addAssetsGroupAlbumWithName:title resultBlock:^(ALAssetsGroup *group) { //coding success } failureBlock:^(NSError *error) { //coding error }]; }
请求所有的照片组
读取所有的资源组对象,其实就是枚举遍历,每次获得一个group对象都会进行一次回调,同步会略微卡顿,所以使用异步回调Block#pragma mark - 读取相册的所有组 /** * 读取相册的所有组 * * @param groupBlock 获取组成功的回调 * @param failBlock 失败的回调 * @param cameraRollHandle 相机胶卷不为nil时候进行的回调 */ -(void)readAllPhotoGroups:(ALAssetGroupBlock)groupBlock Fail:(ALAssetFailBlock)failBlock CameraRollHandel:(void (^)(void))cameraRollHandle { //删除之前存的所有组 [self.groups removeAllObjects]; __block __weak typeof(self) copy_self = self; //开始遍历 [self.library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) { //如果返回的组存在 if (group) { //对group进行过滤,只要照片 [group setAssetsFilter:[ALAssetsFilter allPhotos]]; //添加数据 [copy_self.groups addObject:group]; //进行顺序判断,目的是将胶卷相册放到第一位 if([self containCameraRoll:group] == true) { //删除当前位置的数组 [self.groups removeObjectAtIndex:self.groups.count - 1]; [self.groups insertObject:group atIndex:0]; } //回调数据 groupBlock([NSArray arrayWithArray:copy_self.groups]); //进行序列后的回调 if([self containCameraRoll:group] == true) cameraRollHandle(); } } failureBlock:^(NSError *error) { //失败回调 failBlock(error.localizedDescription); }]; }
这里加载所有的组,所以相机胶卷那个组位置不会是第一个,但是又想它在第一行,增加这个判断来保证存在相机胶卷,为其他操作进行准备:
/** * 判断是否包含相机胶卷 * * @param group ALAssetsGroup对象 * * @return true表示包含,false反之 */ - (BOOL)containCameraRoll:(ALAssetsGroup *)group { //如果是相机胶卷,放到第一位,这里只适配英文以及中文 NSString * nameCN = NSLocalizedString([group valueForProperty:ALAssetsGroupPropertyName], @""); NSString * nameEN = NSLocalizedString([group valueForProperty:ALAssetsGroupPropertyName], @""); //对当前组数进行排序 if ([nameCN isEqualToString:@"相机胶卷"] || [nameEN isEqualToString:@"Camera Roll"]) { //修改变量 return true; } return false; }
请求组中的所有照片资源
1、要想请求组中的资源,首先要打开这个组对象#pragma mark - 打开相片组 -(void)openPhotosGroup:(ALAssetsGroup *)assetsGroup Success:(ALAssetPhotoBlock)successBlock Fail:(ALAssetFailBlock)failBlock { //删除所有的照片对象 [self.photos removeAllObjects]; //避免强引用 __block __weak typeof(self) copy_self = self; //获取当前组的url数据 NSURL * url = [assetsGroup valueForProperty:ALAssetsGroupPropertyURL]; //打开当前的资源组对象 [self.library groupForURL:url resultBlock:^(ALAssetsGroup *group) { [copy_self photosInGroups:group Block:successBlock]; } failureBlock:^(NSError *error) { //失败的回调 failBlock(error.localizedDescription); }]; }
2、在打开的组里面进行遍历并回调数据
//获取所有的照片对象并回调数据 - (void)photosInGroups:(ALAssetsGroup *)group Block:(ALAssetPhotoBlock)photoBlock { //开始读取 [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { //如果不为空或者媒体为图片 if (result != nil && [[result valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypePhoto]) { //添加数据 [self.photos addObject:result]; //数目达标后统一进行回调 if (index == group.numberOfAssets - 1) { //回调 photoBlock([NSArray arrayWithArray:self.photos]); } } }]; }
用到的数据基本都谢了,至于View以及ViewController因为太长,就不在这里占地方了,如果有想法,可以下载代码研究一下。
最后还是要唠叨一句,不管是UIImageView还是UIButton,显示缩略图的时候不要忘记设置contentMode属性,这样才会出现选择展示图中的效果:
//这里表示如果图太大,根据高宽中的最大数值进行展示,所以会有一部分不显示 UIViewContentModeScaleAspectFill //他和上面的属性相反,它是根据高宽终的最小数值进行展示 UIViewContentModeScaleAspectFit
//如果是CollectionCell中进行展示的,设置如下 Self.contentMode = UIViewContentModeScaleAspectFill; //如果是浏览高清图的时候,设置如下 Self.contentMode = UIViewContentModeScaleAspectFit;
相关文章推荐
- IOS、Android html5页面输入的表情符号变成了乱码”???“
- ios开发多线程篇——GCD的常见用法
- iOS中强制转某个页面为横屏,键盘也横屏
- iOS - 系统自带的分享功能
- 史上最全的环信iOS 2.x and 3.x SDK单聊的集成方案!
- iOS 键盘弹出时获取键盘的高度
- ios开发多线程篇——GCD的基本使用
- iOS之在写一个iOS应用之前必须做的7件事(附相关资源)
- iOS获取屏幕亮度和调整屏幕亮度的方法
- iOS之17个提升iOS开发效率的必用工具
- iOS开发 ☞ Commen Sense
- ios开发多线程篇——线程的状态
- block的声明创建以及使用
- iOS OC readOnly 和属性 详解
- iOS 保证视频的清晰度和流畅度
- 关于iOS开发企业应用问题整理
- iOS 定位 <CoreLocation/CoreLocation.h>
- IOS环信3.1 -SDK集成
- iOS学习笔记38-MJExtension使用
- iOS 摇一摇功能的实现