美文网首页
iOS 图片选择器

iOS 图片选择器

作者: 邓布利多教授 | 来源:发表于2019-09-26 14:12 被阅读0次
    • 废话不多说,先看效果图,如果基本满足你的需求就继续看下去,不满足就去找能满足你的。
    • 不知道什么原因这个gif图看着很僵硬呢?简单文字介绍下吧!
    • 图片选择器支持相机拍照和相册选择两种方式,相机拍照的图片应用之后自动保存到相册里;我这里设置的是最大限制图片数是5张,刚好超出屏幕最大宽度,代码里直接设置的是支持左右滑动,不会自动换行。
    gif图.gif
    能继续翻下来的朋友,也许是因为这个小工具满足你的需求,又可能是你根本就不需要,只是想看下怎么实现的,接下来开始正题!

    为了方便,我直接贴代码,该说明的地方都在代码里,我觉得注释的很清楚了,为了节约时间,复制黏贴可以直接用;想要搞清楚原理的朋友们可以时候慢慢看

    1、文件结构

    结构图.png

    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);
    };
    

    7、 全剧终

    demo

    相关文章

      网友评论

          本文标题:iOS 图片选择器

          本文链接:https://www.haomeiwen.com/subject/mzbeyctx.html