此次我用的是三方QBImagePickerController, CTAssetsPickerController也可以, 他们之间的区别暂时我觉得是多选照片时, 前者是对钩√, 后者是排序号1234.., 个人觉得对钩似乎比较好看点就用了前者
注意, 如果要避免进入过一次相册后再进入, 让相册忘记之前选过的图片, 则不能对imagePicker使用懒加载, 每次进入相册都应是new一个新的picker
从图库回来后, 市面上的app基本都是以collectionView呈现多选后的图片, 如果未满最大可选照片数, 最后一个item会覆盖一个加号图片, 以示可以继续添加新的图片
所以创建collectionView就不写了
首先使用cocoaPods导入
pod 'CTAssetsPickerController', '~> 3.3.0'
或者
pod 'QBImagePickerController', '~> 3.4.0'
本次就只写后者
然后引入头文件
#import <QBImagePickerController/QBImagePickerController.h>
然后签协议, 第三个不用说, 后两个是为了可以使用拍照功能
@interface QBViewController ()<UICollectionViewDelegate, UICollectionViewDataSource, QBImagePickerControllerDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
属性
@property (nonatomic, strong) NACollectionView *collectionView;
@property (nonatomic, strong) NAFlowLayout *flowLayout;
@property (nonatomic, strong) NSMutableArray *mArrOfPics;//存储UIImage的数组
@property (nonatomic, strong) QBImagePickerController *imagePickerController;//多选的PickerController
@property (nonatomic, strong) UIImagePickerController *imagePicker;//拍照的PickerController
@property (nonatomic, assign) NSInteger numOfPicCanBeChoosed;//监听距离最大限制数量还有多少张可被选中
如果想自定义相册的navigationBar, 我暂时没什么好办法, 就是点进去QBImagePickerController, 修改init方法中的setUpAlbumsViewController方法, 添加以下三行
//以下这三行我写的
navigationController.navigationBar.barTintColor = [UIColor colorWithRed:0 green:148 / 255.f blue:1 alpha:1];
//按钮字体颜色
navigationController.navigationBar.tintColor = [UIColor whiteColor];
//title字体大小和颜色
[[UINavigationBar appearance] setTitleTextAttributes:@{
NSForegroundColorAttributeName:[UIColor whiteColor],
NSFontAttributeName:[UIFont systemFontOfSize:16 * [UIScreen mainScreen].bounds.size.width / 375]
}];
一开始先把该初始化的初始化, 我设置最多可选6张照片
- (void)viewDidLoad{
[super viewDidLoad];
_numOfPicCanBeChoosed = 6;
_mArrOfPics = [NSMutableArray array];
[self createCollectionView];
}
推出相机的imagePicker还是可以懒加载的
- (UIImagePickerController *)imagePicker{
if (!_imagePicker) {
_imagePicker = [[UIImagePickerController alloc] init];
_imagePicker.delegate = self;
//模态推出照相机页面的样式
_imagePicker.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
// _imagePicker.allowsEditing = YES;
self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
return _imagePicker;
}
#pragma mark - 注销
- (void)dealloc{
self.imagePickerController.delegate = nil;
self.imagePicker.delegate = nil;
}
以下是collectionView三个协议方法, cell上面就是imageView和左上角的删除button, 当没选任何图片或者六张照片全满时, 删除按钮隐藏
#pragma mark - item个数
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
if (_mArrOfPics.count == 0) {
return 1;
}else if(_mArrOfPics.count > 0 && _mArrOfPics.count < 6){
return _mArrOfPics.count + 1;
}
else if(_mArrOfPics.count == 6){
return 6;
}
else{
return 0;
}
}
#pragma mark - 取出cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
NACollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"NACollectionViewCell" forIndexPath:indexPath];
NSLog(@"!!!%ld", _mArrOfPics.count);
//添加了照片
if (_mArrOfPics.count > 0) {
cell.buttonOfDelete.hidden = NO;
for (NSInteger i = 0; i < _mArrOfPics.count; i++) {
UIImage *image = _mArrOfPics[i];
if (indexPath.row == i) {
cell.buttonOfDelete.tag = indexPath.row;
cell.imageViewOfPic.image = image;
}
if (indexPath.row == _mArrOfPics.count) {
cell.imageViewOfPic.image = [UIImage imageNamed:@"add"];
cell.buttonOfDelete.hidden = YES;
}
}
}
//没有添加照片时
else{
cell.buttonOfDelete.hidden = YES;
cell.imageViewOfPic.image = [UIImage imageNamed:@"add"];
}
cell.deletePics = ^(UIButton *button){
if (indexPath.row == button.tag) {
[_mArrOfPics removeObjectAtIndex:indexPath.row];
_numOfPicCanBeChoosed = 6 - _mArrOfPics.count;
[_collectionView reloadData];
}
};
return cell;
}
#pragma mark - 点击item
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
if(_mArrOfPics.count < 6){
if (indexPath.row == _mArrOfPics.count) {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle: UIAlertControllerStyleActionSheet];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *takePicAction = [UIAlertAction actionWithTitle:@"拍照" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self selectImageFromCamera];
}];
UIAlertAction *albumAction = [UIAlertAction actionWithTitle:@"从手机相册选择" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self choosePicFromAlbum];
}];
[alertController addAction:cancelAction];
[alertController addAction:takePicAction];
[alertController addAction:albumAction];
[self presentViewController:alertController animated:YES completion:nil];
}
}
}
选择去相册则对应以下方法
#pragma mark - 从相册选
- (void)choosePicFromAlbum{
//这样就可以让navi顶部与app风格一致
// UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:self.imagePickerController];
_imagePickerController = [[QBImagePickerController alloc] init];
//默认是any
_imagePickerController.mediaType = QBImagePickerMediaTypeImage;
_imagePickerController.assetCollectionSubtypes = @[
@(PHAssetCollectionSubtypeSmartAlbumUserLibrary), // Camera Roll
@(PHAssetCollectionSubtypeAlbumMyPhotoStream), // My Photo Stream
@(PHAssetCollectionSubtypeSmartAlbumPanoramas), // Panoramas
@(PHAssetCollectionSubtypeSmartAlbumVideos), // Videos
@(PHAssetCollectionSubtypeSmartAlbumBursts) // Bursts
];
// _imagePickerController.prompt = @"选择照片";
_imagePickerController.showsNumberOfSelectedAssets = YES;
_imagePickerController.delegate = self;
_imagePickerController.allowsMultipleSelection = YES;
_imagePickerController.maximumNumberOfSelection = 6;
//默认相册显示的预选照片尺寸
_imagePickerController.numberOfColumnsInPortrait = 4;
_imagePickerController.numberOfColumnsInLandscape = 7;
[self presentViewController:self.imagePickerController animated:YES completion:nil];
}
进入相册就连带着调用了一些协议方法, 我选了两个需要用到的时机, 选完后和将要选择某张图片时, 后者是为了阻止超出图片最大限制数量
进入选完图片这个协议方法, 网上很多前辈进行数组初始化, 不, 万一这位用户只想在前面选择基础上继续添加图片呢
#pragma mark - 选完照片
- (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didFinishPickingAssets:(NSArray *)assets {
// _mArrOfPics = [NSMutableArray array];
// 基本配置
CGFloat scale = [UIScreen mainScreen].scale;
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.resizeMode = PHImageRequestOptionsResizeModeNone;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
for (PHAsset *asset in assets) {
CGSize size = CGSizeMake(asset.pixelWidth / scale, asset.pixelHeight / scale);
// 获取图片
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
[_mArrOfPics addObject:result];
self.numOfPicCanBeChoosed = 6 - _mArrOfPics.count;
[_collectionView reloadData];
}];
}
// 关闭图片选择界面
[self dismissViewControllerAnimated:YES completion:nil];
}
接下来是将要选择图片时
#pragma mark - 要选中某张图片之前
- (BOOL)qb_imagePickerController:(QBImagePickerController *)imagePickerController shouldSelectAsset:(PHAsset *)asset{
if(self.imagePickerController.selectedAssets.count + 1 <= self.numOfPicCanBeChoosed){
return YES;
}else{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"一次最多上传6张图片" preferredStyle:UIAlertControllerStyleAlert];
[imagePickerController presentViewController:alert animated:YES completion:nil];
//让alert自动消失
[NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(creatAlert:) userInfo:alert repeats:NO];
return NO;
}
}
#pragma mark - 让警告消失
- (void)creatAlert:(NSTimer *)timer{
UIAlertController *alert = [timer userInfo];
[alert dismissViewControllerAnimated:YES completion:nil];
alert = nil;
}
至于推出相机那部分, 之前有写过, 再写一遍, 区别就是拍照后, 监听剩余可添加图片数的属性变量要更新
#pragma mark - 选择拍照
- (void)selectImageFromCamera{
//判断相机是否可用
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
//判断是否开启相机权限
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
//权限未开启
if (authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied){
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"抱歉" message:@"您尚未开启相机权限" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *actionOK = [UIAlertAction actionWithTitle:@"去开启" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
//info plist中URL type中添加一个URL Schemes添加一个prefs值
if([[UIApplication sharedApplication] canOpenURL:url]){
//跳转到隐私
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=Privacy&path=CAMERA"]];
}
}];
UIAlertAction *actionCancel = [UIAlertAction actionWithTitle:@"不了" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:actionOK];
[alertController addAction:actionCancel];
[self presentViewController:alertController animated:YES completion:nil];
}
//权限已开启
else{
[self presentViewController:self.imagePicker animated:YES completion:^{}];
}
}
//适用于没有相机的设备
else{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"抱歉" message:@"相机不可用" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alertController animated:YES completion:nil];
#pragma mark - 让alert自动消失
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(creatAlert:) userInfo:alertController repeats:NO];
}
}
协议方法, 获取拍照后的图片, 顺便刷新collectionView和监听剩余可选图片的属性
#pragma mark - ImagePicker delegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
//这个本来是想用于拍照后编辑的, 发现并没有用
//self.isFullScreen = NO;
//用拍下来的照片赋值
[_mArrOfPics addObject:image];
[_collectionView reloadData];
self.imagePickerController.maximumNumberOfSelection = 6 - _mArrOfPics.count;
self.numOfPicCanBeChoosed = 6 - _mArrOfPics.count;
//访问相册权限, ios9之后的api, 要引入<Photos/Photos.h>
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
//相册权限已开启
if(status == PHAuthorizationStatusAuthorized){
//存入本地相册
UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
//未开启相册权限
//PHAuthorizationStatusNotDetermined,
//PHAuthorizationStatusRestricted
//PHAuthorizationStatusDenied
else{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"您尚未开启相册权限" message:@"无法存入所拍的照片" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *actionOK = [UIAlertAction actionWithTitle:@"去开启" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
//info plist中URL type中添加一个URL Schemes添加一个prefs值
if([[UIApplication sharedApplication] canOpenURL:url]){
//跳转到隐私
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=Privacy&path=PHOTOS"]];
}
}];
UIAlertAction *actionCancel = [UIAlertAction actionWithTitle:@"不了" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:actionOK];
[alertController addAction:actionCancel];
[self presentViewController:alertController animated:YES completion:nil];
}
[picker dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - 存储到系统相册结果回调
- (void)image:(UIImage*)image didFinishSavingWithError: (NSError*)error contextInfo:(void*)contextInfo{
if (error){
NSLog(@"%@", error);
}
else{
NSLog(@"保存成功");
}
}