iOS开发------简单实现图片多选功能(AssetsLibrary篇)

AssetsLibrary.framework是iOS7.0之前用来获取手机所有的媒体资源的一个静态库,在iOS8.0之后完全可以用Photo.framework来代替,但因为涉及到适配iOS7,所以这个库用的还是比较多的。

实际上,多选图片有很多很好用的第三方,但找到一个完全符合自己需求的第三方也不是那么容易,就算找到,如果不懂,也不是很好修改代码才对,所以了解一下这个库也是很有必要的,这里就记录一下过程中的认识与问题。

如果小伙伴有什么好玩的库,还请介绍一下,很希望能和喜欢钻研技术的你们一起交流。

下面的内容是边看开发文档边研究使用,按自己的理解所写,如果出现错误,也请告知一下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;
时间: 2024-11-05 12:20:56

iOS开发------简单实现图片多选功能(AssetsLibrary篇)的相关文章

iOS开发-简单的图片查看器

现在你只要拿着手机,不管你Android还是iOS,新闻类的App不可避免都有一个功能就是图片查看,做个专题,查看一下内容,App Store中也有专门针对图片浏览的App,鉴于目前所知有限,无法做到那么高大上的App,简单的做个美女查看的Demo.没有太多的功能,上一张,下一张,标签,图片,简简单的,深刻的感觉到知识就是力量,目前知识有限的结果就是Demo简单,且学且珍惜吧. 1.新建项目(如果不会可以参考本人之前的文章),然后在StoryBoard中进行布局,将Girl文件夹中的图片拖入项目

IOS开发-OC学习-常用功能代码片段整理

IOS开发-OC学习-常用功能代码片段整理 IOS开发中会频繁用到一些代码段,用来实现一些固定的功能.比如在文本框中输入完后要让键盘收回,这个需要用一个简单的让文本框失去第一响应者的身份来完成.或者是在做与URL有关的功能时,需要在Info.plist中添加一段代码进而实现让网址完成从Http到Https的转换,以及其他的一些功能. 在从一个新手到逐渐学会各种功能.代码.控件.方法如何使用的过程中,也在逐渐积累一些知识,但是一次总不会把这些东西都深刻记住并完全理解.所以在这儿记录下这些东西,用来

iOS开发项目—07图片拉伸

iOS开发项目—07图片拉伸 一.简单说明 1.代码说明: 图片处理代码: 1 + (UIImage *)resizedImage:(NSString *)name 2 { 3 UIImage *image = [UIImage imageWithName:name]; 4 return [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5]; 5 }

iOS开发-简单解析JSON数据

什么是JSON ? JSON是一种轻量级的数据格式,一般用于数据交互 服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外) ? JSON的格式很像OC中的字典和数组 ? {"name" : "Jack", "age" : 10} {"name" : ["jack", "rose", "jim"]} ? 标准JSON格式的注意点: key必须用双

用jsp实现简单的图片上传功能(multipart/form-data形式的表单)

2008-10-11 22:07 用jsp实现简单的图片上传功能 1 先做一个页面,选择上传的图片<body>   <form action="uploadServlet" enctype="multipart/form-data" method="POST" >           selectimage: <input type="file" name="myfile"/&

iOS开发 GET、POST请求方法:NSURLConnection篇

Web Service使用的主要协议是HTTP协议,即超文本传输协议. HTTP/1.1协议共定义了8种请求方法(OPTIONS.HEAD.GET.POST.PUT.DELETE.TRACE.CONNECT)作为Web服务器. GET方法,是向指定的资源发送请求,请求的参数“显式”地在URL的后面.有点像明信片,把内容“显式”写在外面,因此安全性比较差.一般使用于读取数据.例如从服务器读取静态图片.或查询数据等. POST方法,是向指定资源提交数据,请求服务器进行处理,数据包含在请求体中.参数和

分分钟解决iOS开发中App启动广告的功能

前不久有朋友需要一个启动广告的功能,我说网上有挺多的,他说,看的不是很理想.想让我写一个,于是乎,抽空写了一个,代码通俗易懂,简单的封装了一下,各种事件用block回调的,有俩种样式的广告,一种是全屏广告,另一种是下面露logo的,类似网页新闻的启动广告.依赖SDWebImage主要用来下载网络的广告图片,一般项目里面网络图片都用的这个框架,所以在此不做过多的阐述.下面让我们来看看我封装的过程,对于新手来说,可以学习一下这种封装的思想. 1.首先建一个继承View的LBLaunchImageAd

iOS开发 -文件下载(5 下载功能的封装)

iOS开发网络篇—文件下载(五·下载功能的封装) 一.简单说明 在前面几篇文章介绍下载代码的基础上,此文分析对下载功能进行封装. 通过之前的代码,我们发现仅仅是下载一个文件就需要写很长的代码,那么如果要下载多个文件,就需要写多份代码.在这里,我们把下载一个文件的代码进行封装.控制器只需要知道,下载哪个文件,下载到哪个路径就可以了. 在对下载的功能进行封装后,添加一个文件下载器,一个文件下载器只下载一个文件,封装后如果要下载多个文件的话,那么只需要创建多个文件下载器对象就可以进行控制和下载了. 二

iOS开发——高级技术&amp;摇一摇功能的实现

摇一摇功能的实现 在AppStore中多样化功能越来越多的被使用了,所以今天就开始介绍一些iOS开发的比较实用,但是我们接触的比较少的功能,我们先从摇一摇功能开始 在 UIResponder中存在这么一套方法 1 - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_3_0); 2 3 - (void)motionEnded: