iOS開發從相冊選擇照片或拍照

来源:https://www.cnblogs.com/guozhihe/archive/2020/05/26/12965927.html
-Advertisement-
Play Games

一行代碼搞定圖片選擇 // // gzhPhotoManager.h // 圖片選擇 // // Created by 郭志賀 on 2020/5/26. // Copyright © 2020 郭志賀. All rights reserved. // #import <Foundation/Fou ...


一行代碼搞定圖片選擇

//
//  gzhPhotoManager.h
//  圖片選擇
//
//  Created by 郭志賀 on 2020/5/26.
//  Copyright © 2020 郭志賀. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "ViewController.h"

NS_ASSUME_NONNULL_BEGIN
@protocol gzhPhotoManagerDelegate;
@interface gzhPhotoManager : NSObject

+(instancetype)instance;

/// 選擇圖片
/// @param controller 當前控制器
/// @param target 代理
/// @param pSize 選擇照片尺寸 尺寸傳(0,0)不進行裁剪
- (void)selectPhotoWithController:(UIViewController *)controller delegate:(id)target size:(CGSize)pSize;

@end


@protocol gzhPhotoManagerDelegate <NSObject>

- (void)selectedPhotoImage:(UIImage *)image;

@end
NS_ASSUME_NONNULL_END
  1 //
  2 //  gzhPhotoManager.m
  3 //  圖片選擇
  4 //
  5 //  Created by 郭志賀 on 2020/5/26.
  6 //  Copyright © 2020 郭志賀. All rights reserved.
  7 //
  8 
  9 #import "gzhPhotoManager.h"
 10 #import <MobileCoreServices/MobileCoreServices.h>
 11 #import <Photos/Photos.h>
 12 #import <AssetsLibrary/AssetsLibrary.h>
 13 #import <MetalPerformanceShaders/MetalPerformanceShaders.h>
 14 
 15 @interface gzhPhotoManager () <UINavigationControllerDelegate,UIImagePickerControllerDelegate>
 16 
 17 @property (nonatomic, weak) id<gzhPhotoManagerDelegate> delegate;
 18 @property (nonatomic, assign) CGSize photoSize;
 19 @property (nonatomic, strong) UIImage *image;
 20 @property (nonatomic, weak) UIViewController *controller;
 21 @property (nonatomic, strong) UIImagePickerController *imagePickerController;
 22 
 23 @end
 24 
 25 
 26 @implementation gzhPhotoManager
 27 
 28 + (instancetype)instance {
 29     static gzhPhotoManager * shareInstance = nil;
 30     static dispatch_once_t onceToken;
 31     dispatch_once(&onceToken, ^{
 32         shareInstance = [[gzhPhotoManager alloc]init];
 33     });
 34     return shareInstance;
 35 }
 36 -(void)selectPhotoWithController:(UIViewController *)controller delegate:(id)target size:(CGSize)pSize{
 37     
 38     _controller = controller;
 39     _delegate = target;
 40     _photoSize = pSize;
 41     
 42     UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
 43     [alertVC addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
 44     [alertVC addAction:[UIAlertAction actionWithTitle:@"拍照" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
 45         
 46         [self cameraCheck:action];
 47     }]];
 48     [alertVC addAction:[UIAlertAction actionWithTitle:@"從手機相冊中選擇" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
 49        
 50         [self phAuthorizationCheck:action];
 51     }]];
 52     [_controller presentViewController:alertVC animated:YES completion:nil];
 53 }
 54 -(void)cameraCheck:(UIAlertAction *)action{
 55     /*
 56      AVAuthorizationStatusNotDetermined = 0,// 系統還未知是否訪問,第一次開啟相機時
 57      
 58      AVAuthorizationStatusRestricted, // 受限制的
 59      
 60      AVAuthorizationStatusDenied, //不允許
 61      
 62      AVAuthorizationStatusAuthorized // 允許狀態
 63      */
 64     
 65     ALAuthorizationStatus author =[ALAssetsLibrary authorizationStatus];
 66     if (author == AVAuthorizationStatusRestricted || author ==AVAuthorizationStatusDenied) {
 67         [self alertViewWithTitle:@"提示" message:@"如需拍照,請檢查拍照功能是否開啟,可在:設置->隱私->照相.設置"];
 68     }else if (author == AVAuthorizationStatusAuthorized){
 69         [self selectCamera:action];
 70     }else if (author == AVAuthorizationStatusNotDetermined){
 71         [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
 72             
 73             if (granted) {
 74                 
 75                 //允許訪問
 76                 [self selectCamera:action];
 77             }else{
 78                 
 79                 //不允許訪問
 80                 [self alertViewWithTitle:@"提示" message:@"如需拍照,請檢查拍照功能是否開啟,可在:設置->隱私->照相.設置"];
 81             }
 82             
 83         }];
 84     }
 85     
 86     
 87 }
 88 
 89 //判斷是否有許可權訪問相簿
 90 - (void)phAuthorizationCheck:(UIAlertAction *)action{
 91     /*
 92      PHAuthorizationStatusNotDetermined,     用戶還沒有做出選擇
 93      PHAuthorizationStatusDenied,            用戶拒絕當前應用訪問相冊(用戶當初點擊了"不允許")
 94      PHAuthorizationStatusAuthorized         用戶允許當前應用訪問相冊(用戶當初點擊了"好")
 95      PHAuthorizationStatusRestricted,        因為家長控制, 導致應用無法方法相冊(跟用戶的選擇沒有關係)
 96      */
 97     
 98     // 判斷授權狀態
 99     PHAuthorizationStatus statu = [PHPhotoLibrary authorizationStatus];
100     if (statu == PHAuthorizationStatusRestricted) {
101         NSLog(@"無法訪問相簿--PHAuthorizationStatusRestricted");
102         [self alertViewWithTitle:@"提示" message:@"如需拍照,請檢查拍照功能是否開啟,可在:設置->隱私->照片.設置"];
103     } else if (statu == PHAuthorizationStatusDenied) {
104         NSLog(@"無法訪問相簿--PHAuthorizationStatusDenied");
105         [self alertViewWithTitle:@"提示" message:@"如需拍照,請檢查拍照功能是否開啟,可在:設置->隱私->照片.設置"];
106     } else if (statu == PHAuthorizationStatusAuthorized) {
107         NSLog(@"可以訪問相簿--PHAuthorizationStatusAuthorized");
108         [self selectPhotoLibrary:action];
109     } else if (statu == PHAuthorizationStatusNotDetermined) {
110         // 彈框請求用戶授權
111         NSLog(@"第一次訪問--PHAuthorizationStatusNotDetermined");
112         [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
113             
114             if (status == PHAuthorizationStatusAuthorized) {
115                 [self selectPhotoLibrary:action];
116             }else{
117                 [self alertViewWithTitle:@"提示" message:@"如需拍照,請檢查拍照功能是否開啟,可在:設置->隱私->照片.設置"];
118             }
119             
120         }];
121         
122     }
123     
124     
125 }
126 // 拍照
127 - (void)selectCamera:(UIAlertAction *)action {
128     if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
129         dispatch_async(dispatch_get_main_queue(), ^{
130             [self alertViewWithTitle:@"警告" message:@"對不起,您的設備不存在相機"];
131         });
132         
133         return;
134     }
135 
136 
137     if (!_imagePickerController) {
138         _imagePickerController = [UIImagePickerController new];
139         _imagePickerController.delegate = self;
140     }
141     if (_photoSize.width!=0&&_photoSize.height!=0) {
142         _imagePickerController.allowsEditing = YES;
143     }else{
144         _imagePickerController.allowsEditing = NO;
145     }
146 
147     _imagePickerController.mediaTypes = @[(NSString *)kUTTypeImage];
148     _imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
149     _imagePickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
150     [_controller presentViewController:_imagePickerController animated:YES completion:nil];
151 }
152 
153 // 從相冊中選擇
154 - (void)selectPhotoLibrary:(UIAlertAction *)action {
155     if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
156         dispatch_async(dispatch_get_main_queue(), ^{
157              [self alertViewWithTitle:@"警告" message:@"對不起,您的設備不存在相冊"];
158         });
159       
160     }
161     if (!_imagePickerController) {
162         _imagePickerController = [UIImagePickerController new];
163         _imagePickerController.delegate = self;
164     }
165     if (_photoSize.width!=0&&_photoSize.height!=0) {
166         _imagePickerController.allowsEditing = YES;
167     }else{
168         _imagePickerController.allowsEditing = NO;
169     }
170     _imagePickerController.mediaTypes = @[(NSString *)kUTTypeImage,(NSString *)kUTTypeMovie];
171     _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
172     [_controller presentViewController:_imagePickerController animated:YES completion:nil];
173     
174     
175     
176 }
177 #pragma mark -
178 #pragma mark - UIImagePickerViewController delegate
179 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
180     
181     NSString * mediaType = [info objectForKey:UIImagePickerControllerMediaType];
182     if ([mediaType isEqualToString:(NSString *)kUTTypeImage]){
183         if (_photoSize.height!=0&&_photoSize.width!=0) {
184             UIImage *image = [self fixOrientation:[info objectForKey:UIImagePickerControllerEditedImage]];
185             self.image = [self scaleImage:image Tosize:self.photoSize];
186             if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
187                 UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
188             }
189         }else{
190             UIImage *image = [self fixOrientation:[info objectForKey:UIImagePickerControllerOriginalImage]];
191             self.image = [self scaleImage:image Tosize:self.photoSize];
192             if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
193                 UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
194             }
195         }
196         [picker dismissViewControllerAnimated:YES completion:^{
197             if (self.delegate && [self.delegate respondsToSelector:@selector(selectedPhotoImage:)]) {
198                 if (self.image) {
199                     [self.delegate selectedPhotoImage:self.image];
200                 } else {
201                     [self alertViewWithTitle:@"你還沒選擇圖片呢" message:nil];
202                 }
203             }
204         }];
205     }
206     
207     
208 }
209 
210 -(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
211     [picker dismissViewControllerAnimated:YES completion:nil];
212 }
213 // 裁剪圖片
214 - (UIImage *)scaleImage:(UIImage *)img Tosize:(CGSize)size {
215     
216     CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
217     CGSize imgSize = CGSizeMake(0, 0);
218     if (size.width != 0 && size.height != 0) {
219         imgSize = CGSizeMake(size.width, img.size.height*(size.width/img.size.width));
220     } else {
221         imgSize = CGSizeMake(screenWidth*2, img.size.height*(screenWidth/img.size.width)*2);
222     }
223     // 創建一個bitmap的context
224     // 並把它設置成為當前正在使用的context
225     UIGraphicsBeginImageContext(imgSize);
226     // 繪製改變大小的圖片
227     [img drawInRect:CGRectMake(0, 0, imgSize.width, imgSize.height)];
228     // 從當前context中創建一個改變大小後的圖片
229     UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
230     // 使當前的context出堆棧
231     UIGraphicsEndImageContext();
232     //返回新的改變大小後的圖片
233     return scaledImage;
234 }
235 
236 
237 //修正image方向
238 - (UIImage *)fixOrientation:(UIImage *)aImage {
239     
240 
241     if (aImage.imageOrientation == UIImageOrientationUp)
242         return aImage;
243     
244     CGAffineTransform transform = CGAffineTransformIdentity;
245     
246     switch (aImage.imageOrientation) {
247         case UIImageOrientationDown:
248         case UIImageOrientationDownMirrored:
249             transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
250             transform = CGAffineTransformRotate(transform, M_PI);
251             break;
252             
253         case UIImageOrientationLeft:
254         case UIImageOrientationLeftMirrored:
255             transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
256             transform = CGAffineTransformRotate(transform, M_PI_2);
257             break;
258             
259         case UIImageOrientationRight:
260         case UIImageOrientationRightMirrored:
261             transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
262             transform = CGAffineTransformRotate(transform, -M_PI_2);
263             break;
264         default:
265             break;
266     }
267     
268     switch (aImage.imageOrientation) {
269         case UIImageOrientationUpMirrored:
270         case UIImageOrientationDownMirrored:
271             transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
272             transform = CGAffineTransformScale(transform, -1, 1);
273             break;
274             
275         case UIImageOrientationLeftMirrored:
276         case UIImageOrientationRightMirrored:
277             transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
278             transform = CGAffineTransformScale(transform, -1, 1);
279             break;
280         default:
281             break;
282     }
283 
284     CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
285                                              CGImageGetBitsPerComponent(aImage.CGImage), 0,
286                                              CGImageGetColorSpace(aImage.CGImage),
287                                              CGImageGetBitmapInfo(aImage.CGImage));
288     CGContextConcatCTM(ctx, transform);
289     switch (aImage.imageOrientation) {
290         case UIImageOrientationLeft:
291         case UIImageOrientationLeftMirrored:
292         case UIImageOrientationRight:
293         case UIImageOrientationRightMirrored:
294             // Grr...
295             CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
296             break;
297             
298         default:
299             CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
300             break;
301     }
302     
303     // And now we just create a new UIImage from the drawing context
304     CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
305     UIImage *img = [UIImage imageWithCGImage:cgimg];
306     CGContextRelease(ctx);
307     CGImageRelease(cgimg);
308     return img;
309 }
310 
311 
312 // 提醒
313 - (void)alertViewWithTitle:(NSString *)title message:(NSString *)msg {
314     UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
315     [alertVC addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
316     [_controller presentViewController:alertVC animated:YES completion:nil];
317 }
318 
319 
320 @end

在需要使用的地方遵循<gzhPhotoManagerDelegate>協議

 1 //
 2 //  ViewController.m
 3 //  圖片選擇
 4 //
 5 //  Created by 郭志賀 on 2020/5/26.
 6 //  Copyright © 2020 郭志賀. All rights reserved.
 7 //
 8 
 9 #import "ViewController.h"
10 #import "gzhPhotoManager.h"
11 
12 /** 屏幕高度 */
13 #define ScreenH [UIScreen mainScreen].bounds.size.height
14 /** 屏幕寬度 */
15 #define ScreenW [UIScreen mainScreen].bounds.size.width
16 
17 @interface ViewController ()<gzhPhotoManagerDelegate>
18 @property(nonatomic,strong)UIImageView * selectImageView;
19 @end
20 
21 @implementation ViewController
22 
23 - (void)viewDidLoad {
24     [super viewDidLoad];
25     // Do any additional setup after loading the view.
26     
27     _selectImageView = [[UIImageView alloc]init];
28     _selectImageView.frame = CGRectMake(0, 0, ScreenW, ScreenH);
29     _selectImageView.contentMode = UIViewContentModeScaleAspectFit;
30     _selectImageView.clipsToBounds = YES;
31     _selectImageView.backgroundColor = [UIColor purpleColor];
32     [self.view addSubview:_selectImageView];
33     
34     _selectImageView.userInteractionEnabled = YES;
35     UITapGestureRecognizer * selectPhotoTapGes = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(selectPhoto:)];
36     [_selectImageView addGestureRecognizer:selectPhotoTapGes];
37     
38 }
39 -(void)selectPhoto:(UITapGestureRecognizer *)taps{
40     //調用
41     [[gzhPhotoManager instance]selectPhotoWithController:self delegate:self size:CGSizeMake(ScreenW, ScreenW)];
42     
43 }
44 -(void)selectedPhotoImage:(UIImage *)image{
45     
46     _selectImageView.image = image;
47     
48     
49 }
50 @end

可直接複製使用,新手見解,如有遺漏或不足敬請告知。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • id命令 功能說明:查看指定用戶的ID信息 用法:id [OPTIONS]... [USERNAME] id命令不指定用戶時,則顯示當前用戶的ID。若指定用戶,而不加任何選項時,則顯示用戶ID及所屬組的ID。 選項 作用 -u,--user 僅顯示用戶UID -g,--group 僅顯示用戶的基本組 ...
  • passwd命令 功能說明:設置密碼 用法:passwd [options] [username] 管理員可以使用不帶任何選項的passwd命令修改自己的密碼。 管理員修改任何用戶的密碼都不需要知道用戶原來的密碼,普通用戶僅能更改自己的密碼,且在更改密碼之前,系統會要求用戶輸入現在的密碼,另外普通用 ...
  • 2台主機互為備份,Web服務顯示NFS文件系統上的資源。新增一個Linux6.8的系統作為NFS文件伺服器目錄:1、完成HeartBeat基礎配置2、配置NFS伺服器3、配置HeartBeat資源管理伺服器使用NFS資源4、結果測試1、完成HeartBeat基礎配置基礎配置這裡就不在敘述了,參考下麵... ...
  • 剛纔完成了合同表的變更,到最後一步rename table的時候 ,有個長時間的查詢占用了元數據鎖,導致rename的最後一步不能進行。將該會話kill後rename完成。 ...
  • MySQL的社區版沒有審計功能,企業版才有審計功能。企業版中自帶 Audit Plugin ,名為audit_log.so。但是其它MySQL分支版本也開發了各自的審計功能插件。最常見的就是Percona Audit Log Plugin、MariaDB Audit Plugin、當然還有通用插件M... ...
  • 1.MSC添加shard節點 mkdir -p /mongodb/38027/conf /mongodb/38027/log /mongodb/38027/datamkdir -p /mongodb/38028/conf /mongodb/38028/log /mongodb/38028/datam ...
  • 更多知識,請移步我的小破站:http://hellofriend.top 1. 概述 使用EXPLAIN關鍵字可以模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理你的SQL語句的。分析你的查詢語句或是表結構的性能瓶頸。 通過Explain,我們可以獲取以下信息: 表的讀取順序 哪些索引可以 ...
  • 0.11 版本之前保證的語義是:至少一次 至少一次的解釋 可以做到消息不丟失--> 可以做到發送成功的消息一定可以被消費到。 不能做到消息不重覆。 ## 發送成功的消息,表示業務邏輯認為此消息已發送成功,即send方法已執行完成。 丟消息場景 非同步發送端: a:send之後,等待發送的時候down( ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...