CameraViewController.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. //
  2. // CameraViewController.m
  3. // AIIM
  4. //
  5. // Created by qitewei on 2025/6/5.
  6. //
  7. #import "CameraViewController.h"
  8. @interface CameraViewController ()
  9. @property (nonatomic, strong) CameraUtility *cameraUtility;
  10. @property (nonatomic, strong) UIView *previewView;
  11. @property (nonatomic, strong) UIButton *captureButton;
  12. @property (nonatomic, strong) UIButton *switchCameraButton;
  13. @property (nonatomic, strong) UIButton *flashButton;
  14. @property (nonatomic, strong) UIButton *closeButton;
  15. @property (nonatomic, strong) UIProgressView *progressView;
  16. @property (nonatomic, strong) UILabel *timeLabel;
  17. @property (nonatomic, strong) UIImage * takePictrue;
  18. @property (nonatomic, strong) NSURL * takeVideoURL;
  19. @end
  20. @implementation CameraViewController
  21. - (void)viewDidLoad {
  22. [super viewDidLoad];
  23. [self setupUI];
  24. [self setupCamera];
  25. [self checkCameraPermission];
  26. }
  27. - (void)viewDidLayoutSubviews {
  28. [super viewDidLayoutSubviews];
  29. self.previewView.frame = self.view.bounds;
  30. self.cameraUtility.previewLayer.frame = self.previewView.bounds;
  31. }
  32. - (void)dealloc {
  33. [self.cameraUtility stopRunning];
  34. }
  35. #pragma mark - 初始化设置
  36. - (void)setupUI {
  37. self.view.backgroundColor = [UIColor blackColor];
  38. // 预览视图
  39. self.previewView = [[UIView alloc] initWithFrame:self.view.bounds];
  40. [self.view addSubview:self.previewView];
  41. // 关闭按钮
  42. self.closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
  43. self.closeButton.frame = CGRectMake(20, STATUS_Height + 20, 44, 44);
  44. [self.closeButton setImage:[UIImage imageNamed:@"common_close_white"] forState:UIControlStateNormal];
  45. [self.closeButton addTarget:self action:@selector(closeButtonTapped) forControlEvents:UIControlEventTouchUpInside];
  46. [self.view addSubview:self.closeButton];
  47. // 切换摄像头按钮
  48. self.switchCameraButton = [UIButton buttonWithType:UIButtonTypeCustom];
  49. self.switchCameraButton.frame = CGRectMake(CGRectGetWidth(self.view.frame) - 64, STATUS_Height + 20, 44, 44);
  50. [self.switchCameraButton setImage:[UIImage imageNamed:@"switch_camera"] forState:UIControlStateNormal];
  51. [self.switchCameraButton addTarget:self action:@selector(switchCameraButtonTapped) forControlEvents:UIControlEventTouchUpInside];
  52. [self.view addSubview:self.switchCameraButton];
  53. // 闪光灯按钮
  54. self.flashButton = [UIButton buttonWithType:UIButtonTypeCustom];
  55. self.flashButton.frame = CGRectMake(CGRectGetWidth(self.view.frame) - 64, CGRectGetMaxY(self.switchCameraButton.frame) + 20, 44, 44);
  56. [self.flashButton setImage:[UIImage imageNamed:@"flash_off"] forState:UIControlStateNormal];
  57. [self.flashButton addTarget:self action:@selector(flashButtonTapped) forControlEvents:UIControlEventTouchUpInside];
  58. [self.view addSubview:self.flashButton];
  59. // 拍摄按钮
  60. CGFloat buttonWidth = 70;
  61. self.captureButton = [UIButton buttonWithType:UIButtonTypeCustom];
  62. self.captureButton.frame = CGRectMake((CGRectGetWidth(self.view.frame) - buttonWidth)/2, CGRectGetHeight(self.view.frame) - buttonWidth - 50, buttonWidth, buttonWidth);
  63. self.captureButton.backgroundColor = [UIColor whiteColor];
  64. self.captureButton.layer.cornerRadius = buttonWidth/2;
  65. self.captureButton.layer.masksToBounds = YES;
  66. self.captureButton.layer.borderWidth = 5;
  67. self.captureButton.layer.borderColor = [UIColor colorWithWhite:1 alpha:0.5].CGColor;
  68. [self.view addSubview:self.captureButton];
  69. // 长按手势识别
  70. UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
  71. longPress.minimumPressDuration = 0.3;
  72. [self.captureButton addGestureRecognizer:longPress];
  73. // 单击手势识别
  74. UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
  75. [self.captureButton addGestureRecognizer:tap];
  76. [tap requireGestureRecognizerToFail:longPress];
  77. // 进度条
  78. self.progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
  79. self.progressView.frame = CGRectMake(20, CGRectGetMinY(self.captureButton.frame) - 30, CGRectGetWidth(self.view.frame) - 40, 3);
  80. self.progressView.progressTintColor = [UIColor greenColor];
  81. self.progressView.trackTintColor = [UIColor clearColor];
  82. self.progressView.progress = 0;
  83. self.progressView.hidden = YES;
  84. [self.view addSubview:self.progressView];
  85. // 时间标签
  86. self.timeLabel = [[UILabel alloc] initWithFrame:CGRectMake((CGRectGetWidth(self.view.frame) - 100)/2, CGRectGetMinY(self.progressView.frame) - 30, 100, 20)];
  87. self.timeLabel.textColor = [UIColor whiteColor];
  88. self.timeLabel.textAlignment = NSTextAlignmentCenter;
  89. self.timeLabel.font = [UIFont boldSystemFontOfSize:16];
  90. self.timeLabel.hidden = YES;
  91. [self.view addSubview:self.timeLabel];
  92. }
  93. - (void)setupCamera {
  94. self.cameraUtility = [[CameraUtility alloc] initWithPreviewView:self.previewView];
  95. self.cameraUtility.aspectRatioMode = CameraAspectRatioModeScreen; // 匹配屏幕比例
  96. self.cameraUtility.delegate = self;
  97. }
  98. #pragma mark - 权限检查
  99. - (void)checkCameraPermission {
  100. AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  101. switch (status) {
  102. case AVAuthorizationStatusAuthorized:
  103. [self.cameraUtility startRunning];
  104. break;
  105. case AVAuthorizationStatusNotDetermined: {
  106. [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
  107. dispatch_async(dispatch_get_main_queue(), ^{
  108. if (granted) {
  109. [self.cameraUtility startRunning];
  110. } else {
  111. [self showPermissionDeniedAlert];
  112. }
  113. });
  114. }];
  115. break;
  116. }
  117. default:
  118. [self showPermissionDeniedAlert];
  119. break;
  120. }
  121. }
  122. - (void)showPermissionDeniedAlert {
  123. UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Permission_camera_title", @"")
  124. message:NSLocalizedString(@"Permission_camera_alter", @"")
  125. preferredStyle:UIAlertControllerStyleAlert];
  126. [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Common_cancel", @"") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
  127. [self dismissViewControllerAnimated:YES completion:nil];
  128. }]];
  129. [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Common_goToSetting", @"") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  130. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
  131. }]];
  132. [self presentViewController:alert animated:YES completion:nil];
  133. }
  134. #pragma mark - 按钮事件
  135. - (void)closeButtonTapped {
  136. [self dismissViewControllerAnimated:YES completion:nil];
  137. }
  138. - (void)switchCameraButtonTapped {
  139. [self.cameraUtility switchCamera];
  140. }
  141. - (void)flashButtonTapped {
  142. switch (self.cameraUtility.flashMode) {
  143. case CameraUtilityFlashModeOff:
  144. self.cameraUtility.flashMode = CameraUtilityFlashModeOn;
  145. [self.flashButton setImage:[UIImage imageNamed:@"flash_on"] forState:UIControlStateNormal];
  146. break;
  147. case CameraUtilityFlashModeOn:
  148. self.cameraUtility.flashMode = CameraUtilityFlashModeAuto;
  149. [self.flashButton setImage:[UIImage imageNamed:@"flash_auto"] forState:UIControlStateNormal];
  150. break;
  151. case CameraUtilityFlashModeAuto:
  152. self.cameraUtility.flashMode = CameraUtilityFlashModeOff;
  153. [self.flashButton setImage:[UIImage imageNamed:@"flash_off"] forState:UIControlStateNormal];
  154. break;
  155. }
  156. }
  157. - (void)handleTap:(UITapGestureRecognizer *)gesture {
  158. if (gesture.state == UIGestureRecognizerStateEnded) {
  159. [self.cameraUtility takePhoto];
  160. }
  161. }
  162. - (void)handleLongPress:(UILongPressGestureRecognizer *)gesture {
  163. switch (gesture.state) {
  164. case UIGestureRecognizerStateBegan:
  165. [self startVideoRecording];
  166. break;
  167. case UIGestureRecognizerStateEnded:
  168. case UIGestureRecognizerStateCancelled:
  169. case UIGestureRecognizerStateFailed:
  170. [self stopVideoRecording];
  171. break;
  172. default:
  173. break;
  174. }
  175. }
  176. #pragma mark - 视频录制控制
  177. - (void)startVideoRecording {
  178. self.progressView.hidden = NO;
  179. self.timeLabel.hidden = NO;
  180. self.progressView.progress = 0;
  181. self.timeLabel.text = @"00:00";
  182. [UIView animateWithDuration:0.3 animations:^{
  183. self.captureButton.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.3, 1.3);
  184. self.captureButton.backgroundColor = [UIColor redColor];
  185. }];
  186. [self.cameraUtility startRecordingVideo];
  187. }
  188. - (void)stopVideoRecording {
  189. [UIView animateWithDuration:0.3 animations:^{
  190. self.captureButton.transform = CGAffineTransformIdentity;
  191. self.captureButton.backgroundColor = [UIColor whiteColor];
  192. } completion:^(BOOL finished) {
  193. self.progressView.hidden = YES;
  194. self.timeLabel.hidden = YES;
  195. }];
  196. [self.cameraUtility stopRecordingVideo];
  197. }
  198. #pragma mark - CameraUtilityDelegate
  199. - (void)cameraUtilityDidFinishTakingPhoto:(UIImage *)photo {
  200. // 处理拍摄的照片
  201. self.takePictrue = photo;
  202. [self showPreviewWithImage:photo];
  203. }
  204. - (void)cameraUtilityDidFinishRecordingVideo:(NSURL *)videoURL {
  205. // 处理拍摄的视频
  206. self.takeVideoURL = videoURL;
  207. [self showPreviewWithVideo:videoURL];
  208. }
  209. - (void)cameraUtilityDidOccurError:(NSError *)error {
  210. // 处理错误
  211. NSLog(@"Camera error: %@", error.localizedDescription);
  212. [self showErrorAlert:error.localizedDescription];
  213. }
  214. - (void)cameraUtilityRecordingProgress:(CGFloat)progress {
  215. // 更新录制进度
  216. self.progressView.progress = progress;
  217. // 更新时间显示
  218. NSInteger seconds = (NSInteger)(progress * 60);
  219. self.timeLabel.text = [NSString stringWithFormat:@"00:%02ld", (long)seconds];
  220. }
  221. #pragma mark - 预览处理
  222. - (void)showPreviewWithImage:(UIImage *)image {
  223. // 创建预览视图控制器
  224. UIViewController *previewVC = [[UIViewController alloc] init];
  225. previewVC.view.backgroundColor = [UIColor blackColor];
  226. // 添加图片视图
  227. UIImageView *imageView = [[UIImageView alloc] initWithFrame:previewVC.view.bounds];
  228. imageView.contentMode = UIViewContentModeScaleAspectFit;
  229. imageView.image = image;
  230. [previewVC.view addSubview:imageView];
  231. // 添加操作按钮
  232. UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
  233. backButton.frame = CGRectMake(20, STATUS_Height + 20, 44, 44);
  234. [backButton setImage:[UIImage imageNamed:@"fanhui"] forState:UIControlStateNormal];
  235. [backButton addTarget:self action:@selector(dismissPreview) forControlEvents:UIControlEventTouchUpInside];
  236. [previewVC.view addSubview:backButton];
  237. UIButton *sendButton = [UIButton buttonWithType:UIButtonTypeCustom];
  238. sendButton.frame = CGRectMake(CGRectGetWidth(self.view.frame) - 100, CGRectGetHeight(self.view.frame) - 60, 80, 40);
  239. [sendButton setTitle:NSLocalizedString(@"Common_send", @"") forState:UIControlStateNormal];
  240. [sendButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  241. sendButton.backgroundColor = globalColor(GCTypeGreen);
  242. sendButton.layer.cornerRadius = 4;
  243. [sendButton addTarget:self action:@selector(sendImage:) forControlEvents:UIControlEventTouchUpInside];
  244. [previewVC.view addSubview:sendButton];
  245. // 显示预览
  246. previewVC.modalPresentationStyle = UIModalPresentationFullScreen;
  247. [self presentViewController:previewVC animated:YES completion:nil];
  248. }
  249. - (void)showPreviewWithVideo:(NSURL *)videoURL {
  250. // 创建预览视图控制器
  251. UIViewController *previewVC = [[UIViewController alloc] init];
  252. previewVC.view.backgroundColor = [UIColor blackColor];
  253. // 添加视频播放器
  254. AVPlayer *player = [AVPlayer playerWithURL:videoURL];
  255. AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
  256. playerLayer.frame = previewVC.view.bounds;
  257. [previewVC.view.layer addSublayer:playerLayer];
  258. [player play];
  259. // 添加操作按钮
  260. UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
  261. backButton.frame = CGRectMake(20, STATUS_Height + 20, 44, 44);
  262. [backButton setImage:[UIImage imageNamed:@"fanhui"] forState:UIControlStateNormal];
  263. [backButton addTarget:self action:@selector(dismissPreview) forControlEvents:UIControlEventTouchUpInside];
  264. [previewVC.view addSubview:backButton];
  265. UIButton *sendButton = [UIButton buttonWithType:UIButtonTypeCustom];
  266. sendButton.frame = CGRectMake(CGRectGetWidth(self.view.frame) - 100, CGRectGetHeight(self.view.frame) - 60, 80, 40);
  267. [sendButton setTitle:NSLocalizedString(@"Common_send", @"") forState:UIControlStateNormal];
  268. [sendButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  269. sendButton.backgroundColor = globalColor(GCTypeGreen);
  270. sendButton.layer.cornerRadius = 4;
  271. [sendButton addTarget:self action:@selector(sendVideo:) forControlEvents:UIControlEventTouchUpInside];
  272. [previewVC.view addSubview:sendButton];
  273. // 显示预览
  274. previewVC.modalPresentationStyle = UIModalPresentationFullScreen;
  275. [self presentViewController:previewVC animated:YES completion:nil];
  276. }
  277. #pragma mark - 预览操作
  278. - (void)dismissPreview {
  279. [self dismissViewControllerAnimated:YES completion:nil];
  280. }
  281. - (void)sendImage:(UIButton *)sender {
  282. // 这里实现图片发送逻辑
  283. [self dismissPreview];
  284. [self dismissViewControllerAnimated:YES completion:nil];
  285. !self.takePhotoFinishBlock ?: self.takePhotoFinishBlock(self.takePictrue);
  286. }
  287. - (void)sendVideo:(UIButton *)sender {
  288. // 这里实现视频发送逻辑
  289. [self dismissPreview];
  290. [self dismissViewControllerAnimated:YES completion:nil];
  291. !self.takeVideoFinishBlock ?: self.takeVideoFinishBlock(self.takeVideoURL);
  292. }
  293. #pragma mark - 辅助方法
  294. - (CGFloat)safeAreaTop {
  295. if (@available(iOS 11.0, *)) {
  296. return self.view.safeAreaInsets.top;
  297. }
  298. return 20;
  299. }
  300. - (void)showErrorAlert:(NSString *)message {
  301. UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Common_wrong", @"")
  302. message:message
  303. preferredStyle:UIAlertControllerStyleAlert];
  304. [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Common_confirm", @"") style:UIAlertActionStyleDefault handler:nil]];
  305. [self presentViewController:alert animated:YES completion:nil];
  306. }
  307. - (void)showMessage:(NSString *)message {
  308. UILabel *messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 150, 40)];
  309. messageLabel.center = CGPointMake(self.view.center.x, self.view.center.y - 100);
  310. messageLabel.backgroundColor = [UIColor colorWithWhite:0 alpha:0.7];
  311. messageLabel.textColor = [UIColor whiteColor];
  312. messageLabel.textAlignment = NSTextAlignmentCenter;
  313. messageLabel.text = message;
  314. messageLabel.layer.cornerRadius = 5;
  315. messageLabel.layer.masksToBounds = YES;
  316. [self.view addSubview:messageLabel];
  317. [UIView animateWithDuration:0.3 delay:1.5 options:UIViewAnimationOptionCurveEaseOut animations:^{
  318. messageLabel.alpha = 0;
  319. } completion:^(BOOL finished) {
  320. [messageLabel removeFromSuperview];
  321. }];
  322. }
  323. @end