需求背景
用户相册中会存在10+w的图片,使用airdrop(隔空投送)存在连接不稳定导致传送失败的情况,而且需要批量反复传输。所以开发一款可以在iPhone端批量存储图片的app。
预置条件
1.xcode
2.objective-C或者swift语言基础
实现关键
一、创建视图
1.实现viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self setupView];
[self getPhotoInfor];
}
2.添加控件:类型包含UIImageView、UIButton、UITextView、UILabel
- (void)setupView {
//获取屏幕尺寸
CGRect rc = UIScreen.mainScreen.bounds;
//实现UIImageView
//在屏幕(20,50)的位置,添加一个【长=屏幕宽度-40,高=150】的UITextView
self.textViewInfo = [[UITextView alloc] initWithFrame:CGRectMake(20, 50, rc.size.width-40, 150)];
self.textViewInfo.userInteractionEnabled = NO; //不响应touch、move等动作
self.textViewInfo.backgroundColor = UIColor.grayColor; //控件背景色
self.textViewInfo.textColor = UIColor.blackColor; //控件里文字颜色
[self.view addSubview:self.textViewInfo]; //控件添加到视图中
//实现UIButton
self.btnPick = [[UIButton alloc] initWithFrame:CGRectMake(70, 600, 100, 30)];
self.btnPick.backgroundColor = UIColor.blueColor;
[self.btnPick setTitle:@"选择图片" forState:UIControlStateNormal]; //设置控件名称
//点击控件时,调用"actionOnPickDidClicked"方法
//forControlEvents动作详见说明:https://www.cnblogs.com/whyandinside/archive/2013/10/26/3388908.html
[self.btnPick addTarget:self action:@selector(actionOnPickDidClicked) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.btnPick];
}
3.实现效果图
搭好界面后,就需要具体实现点击操作方法,我们的需求是:
- 点击【选择图片】,调用系统相册或者相机,进行选图/拍照
- 选中的图像展示在imageView中
- 输入需要重复保存的数量,点击【保存图片】,触发图像保存
- 显示当前保存的进度,可以取消保存
二、权限管理
在【选择图片】时,需要有权限管理,在授予照片、相机权限后,才能打开系统相册或者系统相机,此时需要实现“UIImagePickerController”(图像选取器)类的一些方法
以相机权限为例:
- (void)setUpCameraPickControllerIsEdit:(BOOL)isEdit {
self.cameraPicker = [[UIImagePickerController alloc] init];
self.cameraPicker.allowsEditing = isEdit; //拍照选去是否可以截取,和代理中的获取截取后的方法配合使用
self.cameraPicker.delegate = self; //设置代理
self.cameraPicker.sourceType = UIImagePickerControllerSourceTypeCamera;//指定媒体类型是相机/相册/相簿
}
详见:https://blog.csdn.net/qq_36136586/article/details/79074143
- (void)presentChoseActionSheet {
//先创建好 不然调用的时候 第一次创建很慢 有2秒的延迟
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
//判断相机可用
[self setUpCameraPickControllerIsEdit:self.isCutImageBool];
}
[self setUpPhotoPickControllerIsEdit:self.isCutImageBool];
UIAlertController * actionController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet]; //权限弹窗设置
//【取消】按钮的设置
UIAlertAction * cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
//【拍照】按钮的设置
UIAlertAction * takePhotoAction = [UIAlertAction actionWithTitle:@"拍照" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted) {
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:self.cameraPicker animated:YES completion:nil];
});
}
else {
UIAlertController * noticeAlertController = [UIAlertController alertControllerWithTitle:@"未开启相机权限,请到设置界面开启" message:nil preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction * cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
UIAlertAction * okAction = [UIAlertAction actionWithTitle:@"现在就去" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
//跳转到设置界面
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success) {
}];
}];
[noticeAlertController addAction:cancelAction];
[noticeAlertController addAction:okAction];
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:noticeAlertController animated:YES completion:nil];
});
}
}];
}];
[actionController addAction:cancelAction];
[actionController addAction:takePhotoAction];
[self presentViewController:actionController animated:YES completion:^{
}];
}
实现效果
三、图像处理
1.选中的图像需要展示在界面上,以确保选中的图像正确
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissViewControllerAnimated:YES completion:nil];
UIImage *editedimage = [[UIImage alloc] init];
if(self.isCutImageBool){
//获取裁剪的图
editedimage = info[@"UIImagePickerControllerEditedImage"]; //获取裁剪的图
CGSize imageSize = CGSizeMake(413, 626);
if (self.imageSize.height>0) {
imageSize = self.imageSize;
}
editedimage = [self reSizeImage:editedimage toSize:imageSize];
}
else{
editedimage = info[@"UIImagePickerControllerOriginalImage"];
}
NSData *imageData = UIImageJPEGRepresentation(editedimage, 0.0001);//首次进行压缩
UIImage *image = [UIImage imageWithData:imageData];
//图片限制大小不超过 1M CGFloat kb = data.lenth / 1000; 计算kb方法 os 按照千进制计算
while (imageData.length/1000 > 1024) {
NSLog(@"图片超过1M 压缩");
imageData = UIImageJPEGRepresentation(image, 0.5);
image = [UIImage imageWithData:imageData];
}
self.completionHandler(imageData, image);
}
2.选中的图片进行保存
- (void)saveImage {
UIImageWriteToSavedPhotosAlbum(self.imageToSave, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
}
四、异常处理
1.未选择图片、未输入需要保存的数量
- (void)actionOnSaveDidClicked {
self.countToSave = [self.textField.text longLongValue];
if (self.imageToSave == NULL || self.countToSave <= 0) {
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"请选择图片,并输入有效数量" message:@"" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:nil];
});
return;
}
self.labelProgressToSave.textColor=UIColor.blackColor;
self.countSaved = 0;
[self enterSave];
}
- (void)enterSave {
[self dismissViewControllerAnimated:NO completion:nil];
if (self.isCancelSave || self.countSaved >= self.countToSave) {
return;
}
NSString *info = [NSString stringWithFormat:@"保存进度 : 当前第%ld/%ld",self.countSaved+1, self.countToSave];
self.labelProgressToSave.text=info;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self saveImage];
});
}
2.图像保存失败
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
if (error == NULL) {
self.countSaved += 1;
[self enterSave];
} else {
[self dismissViewControllerAnimated:NO completion:nil];
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"保存失败" message:@"重启一下吧" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil];
}
}
3.取消保存
- (void)actionOnCancelDidClicked {
self.countSaved = self.countToSave; //设置当前保存的数量为需要的保存数,即可停止保存了
[self enterSave];
}
最终实现效果
保存图像
取消保存