// // CameraViewController.m // AIIM // // Created by qitewei on 2025/6/5. // #import "CameraViewController.h" @interface CameraViewController () @property (nonatomic, strong) CameraUtility *cameraUtility; @property (nonatomic, strong) UIView *previewView; @property (nonatomic, strong) UIButton *captureButton; @property (nonatomic, strong) UIButton *switchCameraButton; @property (nonatomic, strong) UIButton *flashButton; @property (nonatomic, strong) UIButton *closeButton; @property (nonatomic, strong) UIProgressView *progressView; @property (nonatomic, strong) UILabel *timeLabel; @property (nonatomic, strong) UIImage * takePictrue; @property (nonatomic, strong) NSURL * takeVideoURL; @end @implementation CameraViewController - (void)viewDidLoad { [super viewDidLoad]; [self setupUI]; [self setupCamera]; [self checkCameraPermission]; } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; self.previewView.frame = self.view.bounds; self.cameraUtility.previewLayer.frame = self.previewView.bounds; } - (void)dealloc { [self.cameraUtility stopRunning]; } #pragma mark - 初始化设置 - (void)setupUI { self.view.backgroundColor = [UIColor blackColor]; // 预览视图 self.previewView = [[UIView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:self.previewView]; // 关闭按钮 self.closeButton = [UIButton buttonWithType:UIButtonTypeCustom]; self.closeButton.frame = CGRectMake(20, STATUS_Height + 20, 44, 44); [self.closeButton setImage:[UIImage imageNamed:@"common_close_white"] forState:UIControlStateNormal]; [self.closeButton addTarget:self action:@selector(closeButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:self.closeButton]; // 切换摄像头按钮 self.switchCameraButton = [UIButton buttonWithType:UIButtonTypeCustom]; self.switchCameraButton.frame = CGRectMake(CGRectGetWidth(self.view.frame) - 64, STATUS_Height + 20, 44, 44); [self.switchCameraButton setImage:[UIImage imageNamed:@"switch_camera"] forState:UIControlStateNormal]; [self.switchCameraButton addTarget:self action:@selector(switchCameraButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:self.switchCameraButton]; // 闪光灯按钮 self.flashButton = [UIButton buttonWithType:UIButtonTypeCustom]; self.flashButton.frame = CGRectMake(CGRectGetWidth(self.view.frame) - 64, CGRectGetMaxY(self.switchCameraButton.frame) + 20, 44, 44); [self.flashButton setImage:[UIImage imageNamed:@"flash_off"] forState:UIControlStateNormal]; [self.flashButton addTarget:self action:@selector(flashButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:self.flashButton]; // 拍摄按钮 CGFloat buttonWidth = 70; self.captureButton = [UIButton buttonWithType:UIButtonTypeCustom]; self.captureButton.frame = CGRectMake((CGRectGetWidth(self.view.frame) - buttonWidth)/2, CGRectGetHeight(self.view.frame) - buttonWidth - 50, buttonWidth, buttonWidth); self.captureButton.backgroundColor = [UIColor whiteColor]; self.captureButton.layer.cornerRadius = buttonWidth/2; self.captureButton.layer.masksToBounds = YES; self.captureButton.layer.borderWidth = 5; self.captureButton.layer.borderColor = [UIColor colorWithWhite:1 alpha:0.5].CGColor; [self.view addSubview:self.captureButton]; // 长按手势识别 UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; longPress.minimumPressDuration = 0.3; [self.captureButton addGestureRecognizer:longPress]; // 单击手势识别 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; [self.captureButton addGestureRecognizer:tap]; [tap requireGestureRecognizerToFail:longPress]; // 进度条 self.progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; self.progressView.frame = CGRectMake(20, CGRectGetMinY(self.captureButton.frame) - 30, CGRectGetWidth(self.view.frame) - 40, 3); self.progressView.progressTintColor = [UIColor greenColor]; self.progressView.trackTintColor = [UIColor clearColor]; self.progressView.progress = 0; self.progressView.hidden = YES; [self.view addSubview:self.progressView]; // 时间标签 self.timeLabel = [[UILabel alloc] initWithFrame:CGRectMake((CGRectGetWidth(self.view.frame) - 100)/2, CGRectGetMinY(self.progressView.frame) - 30, 100, 20)]; self.timeLabel.textColor = [UIColor whiteColor]; self.timeLabel.textAlignment = NSTextAlignmentCenter; self.timeLabel.font = [UIFont boldSystemFontOfSize:16]; self.timeLabel.hidden = YES; [self.view addSubview:self.timeLabel]; } - (void)setupCamera { self.cameraUtility = [[CameraUtility alloc] initWithPreviewView:self.previewView]; self.cameraUtility.aspectRatioMode = CameraAspectRatioModeScreen; // 匹配屏幕比例 self.cameraUtility.delegate = self; } #pragma mark - 权限检查 - (void)checkCameraPermission { AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; switch (status) { case AVAuthorizationStatusAuthorized: [self.cameraUtility startRunning]; break; case AVAuthorizationStatusNotDetermined: { [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { dispatch_async(dispatch_get_main_queue(), ^{ if (granted) { [self.cameraUtility startRunning]; } else { [self showPermissionDeniedAlert]; } }); }]; break; } default: [self showPermissionDeniedAlert]; break; } } - (void)showPermissionDeniedAlert { UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Permission_camera_title", @"") message:NSLocalizedString(@"Permission_camera_alter", @"") preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Common_cancel", @"") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { [self dismissViewControllerAnimated:YES completion:nil]; }]]; [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Common_goToSetting", @"") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil]; }]]; [self presentViewController:alert animated:YES completion:nil]; } #pragma mark - 按钮事件 - (void)closeButtonTapped { [self dismissViewControllerAnimated:YES completion:nil]; } - (void)switchCameraButtonTapped { [self.cameraUtility switchCamera]; } - (void)flashButtonTapped { switch (self.cameraUtility.flashMode) { case CameraUtilityFlashModeOff: self.cameraUtility.flashMode = CameraUtilityFlashModeOn; [self.flashButton setImage:[UIImage imageNamed:@"flash_on"] forState:UIControlStateNormal]; break; case CameraUtilityFlashModeOn: self.cameraUtility.flashMode = CameraUtilityFlashModeAuto; [self.flashButton setImage:[UIImage imageNamed:@"flash_auto"] forState:UIControlStateNormal]; break; case CameraUtilityFlashModeAuto: self.cameraUtility.flashMode = CameraUtilityFlashModeOff; [self.flashButton setImage:[UIImage imageNamed:@"flash_off"] forState:UIControlStateNormal]; break; } } - (void)handleTap:(UITapGestureRecognizer *)gesture { if (gesture.state == UIGestureRecognizerStateEnded) { [self.cameraUtility takePhoto]; } } - (void)handleLongPress:(UILongPressGestureRecognizer *)gesture { switch (gesture.state) { case UIGestureRecognizerStateBegan: [self startVideoRecording]; break; case UIGestureRecognizerStateEnded: case UIGestureRecognizerStateCancelled: case UIGestureRecognizerStateFailed: [self stopVideoRecording]; break; default: break; } } #pragma mark - 视频录制控制 - (void)startVideoRecording { self.progressView.hidden = NO; self.timeLabel.hidden = NO; self.progressView.progress = 0; self.timeLabel.text = @"00:00"; [UIView animateWithDuration:0.3 animations:^{ self.captureButton.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.3, 1.3); self.captureButton.backgroundColor = [UIColor redColor]; }]; [self.cameraUtility startRecordingVideo]; } - (void)stopVideoRecording { [UIView animateWithDuration:0.3 animations:^{ self.captureButton.transform = CGAffineTransformIdentity; self.captureButton.backgroundColor = [UIColor whiteColor]; } completion:^(BOOL finished) { self.progressView.hidden = YES; self.timeLabel.hidden = YES; }]; [self.cameraUtility stopRecordingVideo]; } #pragma mark - CameraUtilityDelegate - (void)cameraUtilityDidFinishTakingPhoto:(UIImage *)photo { // 处理拍摄的照片 self.takePictrue = photo; [self showPreviewWithImage:photo]; } - (void)cameraUtilityDidFinishRecordingVideo:(NSURL *)videoURL { // 处理拍摄的视频 self.takeVideoURL = videoURL; [self showPreviewWithVideo:videoURL]; } - (void)cameraUtilityDidOccurError:(NSError *)error { // 处理错误 NSLog(@"Camera error: %@", error.localizedDescription); [self showErrorAlert:error.localizedDescription]; } - (void)cameraUtilityRecordingProgress:(CGFloat)progress { // 更新录制进度 self.progressView.progress = progress; // 更新时间显示 NSInteger seconds = (NSInteger)(progress * 60); self.timeLabel.text = [NSString stringWithFormat:@"00:%02ld", (long)seconds]; } #pragma mark - 预览处理 - (void)showPreviewWithImage:(UIImage *)image { // 创建预览视图控制器 UIViewController *previewVC = [[UIViewController alloc] init]; previewVC.view.backgroundColor = [UIColor blackColor]; // 添加图片视图 UIImageView *imageView = [[UIImageView alloc] initWithFrame:previewVC.view.bounds]; imageView.contentMode = UIViewContentModeScaleAspectFit; imageView.image = image; [previewVC.view addSubview:imageView]; // 添加操作按钮 UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom]; backButton.frame = CGRectMake(20, STATUS_Height + 20, 44, 44); [backButton setImage:[UIImage imageNamed:@"fanhui"] forState:UIControlStateNormal]; [backButton addTarget:self action:@selector(dismissPreview) forControlEvents:UIControlEventTouchUpInside]; [previewVC.view addSubview:backButton]; UIButton *sendButton = [UIButton buttonWithType:UIButtonTypeCustom]; sendButton.frame = CGRectMake(CGRectGetWidth(self.view.frame) - 100, CGRectGetHeight(self.view.frame) - 60, 80, 40); [sendButton setTitle:NSLocalizedString(@"Common_send", @"") forState:UIControlStateNormal]; [sendButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; sendButton.backgroundColor = globalColor(GCTypeGreen); sendButton.layer.cornerRadius = 4; [sendButton addTarget:self action:@selector(sendImage:) forControlEvents:UIControlEventTouchUpInside]; [previewVC.view addSubview:sendButton]; // 显示预览 previewVC.modalPresentationStyle = UIModalPresentationFullScreen; [self presentViewController:previewVC animated:YES completion:nil]; } - (void)showPreviewWithVideo:(NSURL *)videoURL { // 创建预览视图控制器 UIViewController *previewVC = [[UIViewController alloc] init]; previewVC.view.backgroundColor = [UIColor blackColor]; // 添加视频播放器 AVPlayer *player = [AVPlayer playerWithURL:videoURL]; AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player]; playerLayer.frame = previewVC.view.bounds; [previewVC.view.layer addSublayer:playerLayer]; [player play]; // 添加操作按钮 UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom]; backButton.frame = CGRectMake(20, STATUS_Height + 20, 44, 44); [backButton setImage:[UIImage imageNamed:@"fanhui"] forState:UIControlStateNormal]; [backButton addTarget:self action:@selector(dismissPreview) forControlEvents:UIControlEventTouchUpInside]; [previewVC.view addSubview:backButton]; UIButton *sendButton = [UIButton buttonWithType:UIButtonTypeCustom]; sendButton.frame = CGRectMake(CGRectGetWidth(self.view.frame) - 100, CGRectGetHeight(self.view.frame) - 60, 80, 40); [sendButton setTitle:NSLocalizedString(@"Common_send", @"") forState:UIControlStateNormal]; [sendButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; sendButton.backgroundColor = globalColor(GCTypeGreen); sendButton.layer.cornerRadius = 4; [sendButton addTarget:self action:@selector(sendVideo:) forControlEvents:UIControlEventTouchUpInside]; [previewVC.view addSubview:sendButton]; // 显示预览 previewVC.modalPresentationStyle = UIModalPresentationFullScreen; [self presentViewController:previewVC animated:YES completion:nil]; } #pragma mark - 预览操作 - (void)dismissPreview { [self dismissViewControllerAnimated:YES completion:nil]; } - (void)sendImage:(UIButton *)sender { // 这里实现图片发送逻辑 [self dismissPreview]; [self dismissViewControllerAnimated:YES completion:nil]; !self.takePhotoFinishBlock ?: self.takePhotoFinishBlock(self.takePictrue); } - (void)sendVideo:(UIButton *)sender { // 这里实现视频发送逻辑 [self dismissPreview]; [self dismissViewControllerAnimated:YES completion:nil]; !self.takeVideoFinishBlock ?: self.takeVideoFinishBlock(self.takeVideoURL); } #pragma mark - 辅助方法 - (CGFloat)safeAreaTop { if (@available(iOS 11.0, *)) { return self.view.safeAreaInsets.top; } return 20; } - (void)showErrorAlert:(NSString *)message { UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Common_wrong", @"") message:message preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Common_confirm", @"") style:UIAlertActionStyleDefault handler:nil]]; [self presentViewController:alert animated:YES completion:nil]; } - (void)showMessage:(NSString *)message { UILabel *messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 150, 40)]; messageLabel.center = CGPointMake(self.view.center.x, self.view.center.y - 100); messageLabel.backgroundColor = [UIColor colorWithWhite:0 alpha:0.7]; messageLabel.textColor = [UIColor whiteColor]; messageLabel.textAlignment = NSTextAlignmentCenter; messageLabel.text = message; messageLabel.layer.cornerRadius = 5; messageLabel.layer.masksToBounds = YES; [self.view addSubview:messageLabel]; [UIView animateWithDuration:0.3 delay:1.5 options:UIViewAnimationOptionCurveEaseOut animations:^{ messageLabel.alpha = 0; } completion:^(BOOL finished) { [messageLabel removeFromSuperview]; }]; } @end