| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- //
- // 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
|