- 废话不多说,先看效果图,如果基本满足你的需求就继续看下去,不满足就去找能满足你的。
- 不知道什么原因这个gif图看着很僵硬呢?简单文字介绍下吧!
- 图片选择器支持相机拍照和相册选择两种方式,相机拍照的图片应用之后自动保存到相册里;我这里设置的是最大限制图片数是5张,刚好超出屏幕最大宽度,代码里直接设置的是支持左右滑动,不会自动换行。
能继续翻下来的朋友,也许是因为这个小工具满足你的需求,又可能是你根本就不需要,只是想看下怎么实现的,接下来开始正题!
为了方便,我直接贴代码,该说明的地方都在代码里,我觉得注释的很清楚了,为了节约时间,复制黏贴可以直接用;想要搞清楚原理的朋友们可以时候慢慢看
1、文件结构
2、相机小封装
- .h文件
#import <Foundation/Foundation.h>
typedef void (^ LYCameraBlock)(NSData *data);
@interface LYCamera : NSObject
+(LYCamera *)shareInit;
@property (nonatomic, copy)LYCameraBlock lyCameraBlock;
-(void)openWithView:(UIViewController *)view Block:(LYCameraBlock)block;
@end
- .m文件
#import "LYCamera.h"
#import <AVFoundation/AVFoundation.h>
@interface LYCamera ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate,UIActionSheetDelegate>
@property (nonatomic, strong) UIViewController *view;
@end
@implementation LYCamera
+(LYCamera *)shareInit{
static LYCamera *data = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
data = [[LYCamera alloc] init];
});
return data;
}
-(void)openWithView:(UIViewController *)view Block:(LYCameraBlock)block{
_view = view;
_lyCameraBlock = block;
NSString *mediaType = AVMediaTypeVideo;//读取媒体类型
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];//读取设备授权状态
if(authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied){
[[[LYAlertController alloc]init] showWithController:_view Message:@"允许打开相机" Confirm:^{
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
[[UIApplication sharedApplication] openURL:url];
}];
}else{
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:nil
delegate:self
cancelButtonTitle:@"取消"
destructiveButtonTitle:nil
otherButtonTitles:@"拍照",@"相册",nil];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[actionSheet showInView:_view.view];
}
}
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0) {
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
NSLog(@"失败");
}else{
UIImagePickerController * imagePicker = [[UIImagePickerController alloc]init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;//设置源类型
// [imagePicker setEditing:YES animated:YES];//允许编辑
// imagePicker.allowsEditing = YES;
[_view presentViewController:imagePicker animated:YES completion:nil];
}
}else if (buttonIndex == 1){
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]){
UIImagePickerController * imagePicker = [[UIImagePickerController alloc]init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;//设置源类型
// [imagePicker setEditing:YES animated:YES];//允许编辑
// imagePicker.allowsEditing = YES;
[_view presentViewController:imagePicker animated:YES completion:nil];
}
}
}
//打开相册之后选择的方法
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
NSString * mediaType = [info valueForKey:UIImagePickerControllerMediaType];
__weak typeof(self) wSelf = self;
if ([mediaType hasSuffix:@"image"]){
// UIImage *image = [info valueForKey:UIImagePickerControllerEditedImage];//允许编辑
UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage];
//返回的就是jpeg格式的data
NSData *dataImage = UIImageJPEGRepresentation(image, 0.5);
if (picker.sourceType != UIImagePickerControllerSourceTypePhotoLibrary) {
//把图片保存到相册
[self saveImageToPhotos:image];
}
[_view dismissViewControllerAnimated:YES completion:^{
if (wSelf.lyCameraBlock) {
wSelf.lyCameraBlock(dataImage);
}
}];
}
}
//实现该方法
- (void)saveImageToPhotos:(UIImage*)savedImage{
//因为需要知道该操作的完成情况,即保存成功与否,所以此处需要一个回调方法image:didFinishSavingWithError:contextInfo:
UIImageWriteToSavedPhotosAlbum(savedImage, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
}
//回调方法
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
NSString *msg = nil;
if(error != NULL){
msg = @"保存失败";
}else{
msg = @"保存成功";
}
// [WKProgressHUD popMessage:msg inView:[UIApplication sharedApplication].keyWindow duration:1.0 animated:YES];
}
@end
3、存储图片小Model
- .h文件
#import <Foundation/Foundation.h>
@interface LYUploadImgModel : NSObject
@property (nonatomic, strong) UIImage *img;
/**
0 表示手动上传的图片
1 表示默认的占位图片
*/
@property (nonatomic) NSInteger imgType;
@end
- .m文件
#import "LYUploadImgModel.h"
@implementation LYUploadImgModel
@end
4、展示图片小Cell
- .h文件
#import <UIKit/UIKit.h>
@class LYUploadImgModel;
@interface LYUploadImgViewCell : UICollectionViewCell
-(void)setDataSourceWithModel:(LYUploadImgModel *)model Index:(NSInteger)index;
-(void)deleteImgSelectWithBlock:(void (^)(NSInteger index))block;
@end
- .m文件
#import "LYUploadImgViewCell.h"
#import "LYUploadImgModel.h"
typedef void(^ DeleteBlock)(NSInteger);
@interface LYUploadImgViewCell ()
@property (nonatomic, strong) UIImageView *ivImg;
@property (nonatomic, strong) UIButton *bDelete;
@property (nonatomic) NSInteger index;
@property (nonatomic, copy) DeleteBlock block;
@end
@implementation LYUploadImgViewCell
-(instancetype)initWithFrame:(CGRect)frame
{
if (self == [super initWithFrame:frame]) {
self.backgroundColor = [UIColor whiteColor];
//图片
self.ivImg = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
self.ivImg.backgroundColor = [UIColor whiteColor];
self.ivImg.layer.cornerRadius = 5;
self.ivImg.layer.masksToBounds = YES;
[self addSubview:self.ivImg];
//删除按钮
CGFloat btnWidth = 15;
self.bDelete = [[UIButton alloc] initWithFrame:CGRectMake(self.frame.size.width - btnWidth, 0, btnWidth, btnWidth)];
[self.bDelete setImage:LYImageName(@"icon_delete_img") forState:UIControlStateNormal];
self.bDelete.backgroundColor = [UIColor whiteColor];
self.bDelete.layer.cornerRadius = btnWidth / 2;
self.bDelete.layer.masksToBounds = YES;
[self.bDelete addTarget:self action:@selector(deleteAction) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.bDelete];
}
return self;
}
-(void)deleteAction{
if (_block) {
_block(_index);
}
}
-(void)deleteImgSelectWithBlock:(void (^)(NSInteger))block{
_block = block;
}
-(void)setDataSourceWithModel:(LYUploadImgModel *)model Index:(NSInteger)index{
_index = index;
[self.ivImg setImage:model.img];
//占位图的时候不显示删除按钮
if (model.imgType == 1) {
self.ivImg.layer.cornerRadius = 0;
self.bDelete.hidden = YES;
}
//非占位图的时候显示删除按钮
else{
self.ivImg.layer.cornerRadius = 5;
self.bDelete.hidden = NO;
}
}
@end
5、正规军 — 图片选择器
- .h文件
#import <UIKit/UIKit.h>
typedef void (^ LYUploadImgViewBlock)(NSMutableArray *imgDataSource);
@interface LYUploadImgView : UIView
@property (nonatomic, copy) LYUploadImgViewBlock block;
@property (nonatomic) NSInteger maxCount;
@end
- .m文件
#import "LYUploadImgView.h"
#import "LYUploadImgViewCell.h"
#import "LYUploadImgModel.h"
static NSString *ident = @"Item";
@interface LYUploadImgView ()<UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout>
@property (nonatomic) NSInteger maxDefaultCount;//默认最大上传数量,最多5张
@property (nonatomic) NSInteger currentImgCount;//当前上传图片数量
@property (nonatomic, strong) UIButton *buttonUpload;//上传图片按钮
@property (nonatomic, strong) UICollectionViewFlowLayout *layout;
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) NSMutableArray *dataSource;//数据源数组
@property (nonatomic, strong) NSMutableArray *imgDataSource;//回调的上传图片数组
@end
@implementation LYUploadImgView
-(instancetype)init{
if (self == [super init]) {
self.backgroundColor = [UIColor whiteColor];
[self createUI];
[self initDataSource];
}
return self;
}
-(void)layoutSubviews{
[super layoutSubviews];
_layout.itemSize = CGSizeMake(self.frame.size.height, self.frame.size.height);
_collectionView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
_buttonUpload.frame = CGRectMake(0, 0, self.frame.size.height, self.frame.size.height);
}
#pragma mark - 创建UI
-(void)createUI{
[self addSubview:self.buttonUpload];
[self addSubview:self.collectionView];
[self isHideUploadView:NO];
}
#pragma mark - 控制上传按钮和Collection的隐藏与显示
-(void)isHideUploadView:(BOOL)isHide{
self.buttonUpload.hidden = isHide;
self.collectionView.hidden = !isHide;
}
#pragma mark - 添加图片按钮
-(UIButton *)buttonUpload{
if (!_buttonUpload) {
_buttonUpload = [[UIButton alloc] init];
[_buttonUpload setImage:LYImageName(@"icon_add_img") forState:0];
[_buttonUpload addTarget:self action:@selector(buttonUploadSelect:) forControlEvents:UIControlEventTouchUpInside];
}
return _buttonUpload;
}
-(void)buttonUploadSelect:(UIButton *)btn{
__weak typeof(self) wSelf = self;
//调起相机
[[LYCamera shareInit] openWithView:SuperController(self) Block:^(NSData *data) {
//判断上传图片数量是否小于最大限制
if (self.currentImgCount < self.maxDefaultCount) {
LYUploadImgModel *model = [[LYUploadImgModel alloc] init];
model.img = [UIImage imageWithData:data];
model.imgType = 0;
[self.dataSource insertObject:model atIndex:self.dataSource.count-1];//新上传的图片存储位置永远都在默认图片的前面
if (wSelf.block) {
//图片转码base64,存储并回调出去
NSString *encodedImageStr = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
[self.imgDataSource addObject:encodedImageStr];
wSelf.block(self.imgDataSource);
}
}
//先把currentImgCount置0,然后遍历手动上传图片的个数,并记录
self.currentImgCount = 0;
for (LYUploadImgModel *model in self.dataSource) {
if (model.imgType == 0) {
self.currentImgCount ++;
}
}
//手动上传图片的个数大于等于最大限制数时,移除最后一个占位图
if (self.currentImgCount >= self.maxDefaultCount) {
[self.dataSource removeObjectAtIndex:self.maxDefaultCount];
}
[self.collectionView reloadData];
[self isHideUploadView:YES];
}];
}
#pragma mark - CollectionView
-(UICollectionView *)collectionView{
if (!_collectionView) {
_layout = [[UICollectionViewFlowLayout alloc] init];
_layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
_layout.minimumLineSpacing = 10;
_layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0);
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_layout];
_collectionView.backgroundColor = [UIColor whiteColor];
_collectionView.showsHorizontalScrollIndicator = NO;
_collectionView.userInteractionEnabled = YES;
[_collectionView registerClass:[LYUploadImgViewCell class] forCellWithReuseIdentifier:ident];
_collectionView.delegate = self;
_collectionView.dataSource = self;
}
return _collectionView;
}
#pragma mark -- UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return self.dataSource.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
LYUploadImgViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ident forIndexPath:indexPath];
LYUploadImgModel *model = self.dataSource[indexPath.row];
[cell setDataSourceWithModel:model Index:indexPath.row];
//删除已上传图片的回调
__weak typeof(self) wSelf = self;
[cell deleteImgSelectWithBlock:^(NSInteger index) {
//移除源数据数组中对应位置的图片
[self.dataSource removeObjectAtIndex:index];
if (wSelf.block) {
//从回调数组中移除对应位置的图片,并回调出去
[wSelf.imgDataSource removeObjectAtIndex:index];
wSelf.block(wSelf.imgDataSource);
}
//遍历占位图是否存在,存在立刻结束遍历,并跳出当前方法
BOOL isCancel = NO;
for (LYUploadImgModel *model in self.dataSource) {
if (model.imgType == 1) {
isCancel = YES;
break;
}
}
//如果占位图不存在,重新添加占位图到源数组中
if (!isCancel) {
[self initModel];
}
[self.collectionView reloadData];
//先把currentImgCount置0,然后遍历手动上传图片的个数,并记录
self.currentImgCount = 0;
for (LYUploadImgModel *model in self.dataSource) {
if (model.imgType == 0) {
self.currentImgCount ++;
}
}
//如果手动上传图片个数为0,恢复初始状态
if (self.currentImgCount == 0) {
[self isHideUploadView:NO];
}
}];
return cell;
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
if (self.currentImgCount < self.maxDefaultCount) {
if (indexPath.row == (self.dataSource.count-1)) {
[self buttonUploadSelect:nil];
}
}
}
#pragma mark - 数据源
-(NSMutableArray *)dataSource{
if (!_dataSource) {
_dataSource = [NSMutableArray new];
}
return _dataSource;
}
-(NSMutableArray *)imgDataSource{
if (!_imgDataSource) {
_imgDataSource = [NSMutableArray new];
}
return _imgDataSource;
}
#pragma mark - 初始化数据源
-(void)initDataSource{
self.currentImgCount = 0;
self.maxDefaultCount = 5;
[self initModel];
}
-(void)initModel{
LYUploadImgModel *model = [[LYUploadImgModel alloc] init];
UIImage *img = LYImageName(@"icon_add_img");
model.img = img;
model.imgType = 1;
[self.dataSource addObject:model];
}
-(void)setMaxCount:(NSInteger)maxCount{
self.maxDefaultCount = maxCount;//最大限制数根据设置重新赋值
}
@end
6、调用
引入头文件
#import "LYUploadImgView.h"
- 初始化
LYUploadImgView *selector = [LYUploadImgView new];
[self addSubview:selector];
[selector mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.lOrderNo.mas_left);
make.top.mas_equalTo(self.lVoucher.mas_bottom).offset(10);
make.right.mas_equalTo(self.tvExplain.mas_right);
make.height.mas_equalTo(75);
}];
- 图片回调
selector.block = ^(NSMutableArray *imgDataSource) {
NSLog(@"imgDataSource = %@",imgDataSource);
};