如何检测用户何时点击“录制” UIImagePickerController 中的按钮?

发布于 2024-10-16 04:49:03 字数 802 浏览 5 评论 0原文

我想在用户点击 UIImagePicker 控制器中的记录按钮时显示倒计时,但没有委托方法告诉我们他们何时点击记录。我可以设置最长持续时间,但我想给出 1 分钟警告或类似效果,但我不知道如何执行该

videoPickerCtrl = [[UIImagePickerController alloc] init];
videoPickerCtrl.delegate = self;
videoPickerCtrl.sourceType =      UIImagePickerControllerSourceTypeCamera;
videoPickerCtrl.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:videoPickerCtrl.sourceType];   
videoPickerCtrl.allowsEditing = NO;
videoPickerCtrl.videoMaximumDuration = 170;
videoPickerCtrl.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeMovie];

操作编辑:

我找不到解决方案,所以我做了自己的自定义视频选择器控制器。希望其他人能发现它有用: https://github.com/saliksyed/CustomVideoCapture

I would like to show a countdown when the user hits the record button in the UIImagePicker controller but there is no delegate method telling us when they hit record. I'm able to set a max duration but I would like to give a 1 minute warning or something to that effect but I'm not sure how to do that

videoPickerCtrl = [[UIImagePickerController alloc] init];
videoPickerCtrl.delegate = self;
videoPickerCtrl.sourceType =      UIImagePickerControllerSourceTypeCamera;
videoPickerCtrl.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:videoPickerCtrl.sourceType];   
videoPickerCtrl.allowsEditing = NO;
videoPickerCtrl.videoMaximumDuration = 170;
videoPickerCtrl.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeMovie];

EDIT:

I could not find a solution to this so I made my own custom video picker controller. Hopefully someone else can find it useful:
https://github.com/saliksyed/CustomVideoCapture

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

我的痛♀有谁懂 2024-10-23 04:49:03

在一个完美的世界中,你会希望苹果只提供几个代表来做这件事。例如:

  • (void)imagePickerControllerDidStartVideoCapturing:(UIImagePickerController *)picker
  • (void)imagePickerControllerDidStopVideoCapturing:(UIImagePickerController *)picker

然而现实(根据苹果文档)是:

  • UIImagePickerController 的协议太基础了,无法做到这一点
  • 这个类旨在使用按原样并且不支持子类化
  • 此类的视图层次结构是私有的,不得修改

文档还指出:“您可以将自定义视图分配给cameraOverlayView属性并使用该视图来呈现附加信息或管理相机接口和您的代码”。

在我的应用程序中,我需要呈现“UIProgressView”来指示视频可以录制多长时间。为了实现这一点,我需要能够检测视频捕捉开始的时刻。

我不想禁用本机相机控件,因为它们很酷,而且我很懒,所以我不想花太多时间重新发明轮子。我所需要的只是捕获一个大的红色按钮被点击以开始或停止录制的事实。

我的解决方案是用自定义视图“覆盖”原始的开始/停止录制按钮,并为该视图启用用户交互,如下所示:

overlayView = [[UIView alloc] initWithFrame:self.view.frame];

// Start/ Stop fake button
UIView *ssView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width / 2 - 35, self.view.frame.size.height - 71, 70, 70)];
[ssView setUserInteractionEnabled:YES];

// Background color below is only there to make sure my pseudo-button overlaps native Start/Stop button. Comment out the line below to leave it transparent
[ssView setBackgroundColor:[UIColor colorWithRed:0 green:1 blue:0 alpha:0.5f]];

UITapGestureRecognizer *t = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
[ssView addGestureRecognizer:t];

[overlayView addSubview:ssView];  

// My own progress bar
UIProgressView *p = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
[p setTintColor:[UIColor redColor]];
[p setCenter:CGPointMake(30, 130)];
[p setTransform:CGAffineTransformMakeRotation( M_PI / 2 )];
[p setProgress:0];

[overlayView addSubview:p];

pickerController.cameraOverlayView = overlayView;

然后我为点击定义了事件处理程序,如下所示:

-(void)tapped:(id)sender {

    if (isRecording) {
        [pickerController stopVideoCapture];
        NSLog(@"Video capturing stopped...");
        // add your business logic here ie stop updating progress bar etc...
        [pickerController.cameraOverlayView setHidden:YES];
        isRecording = NO;
        return;
    }

    if ([pickerController startVideoCapture]) {
        NSLog(@"Video capturing started...");
        // add your business logic here ie start updating progress bar etc...
        isRecording = YES;
    }

}

接口文件的完整代码:

#import <UIKit/UIKit.h>
#import <MobileCoreServices/MobileCoreServices.h>

@interface ViewController : UIViewController <UIImagePickerControllerDelegate>
- (IBAction)openCamera:(id)sender;

@end

实现文件:

#import "ViewController.h"

@interface ViewController () {
    UIImagePickerController *pickerController;
    UIView* overlayView;
    BOOL isRecording;
}

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    isRecording = NO;

    pickerController = [[UIImagePickerController alloc] init];
    pickerController.delegate = self;
    pickerController.allowsEditing = NO;
    pickerController.videoMaximumDuration = 30.0f;
    pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
    pickerController.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil];

    // I want default controls be available here...
    pickerController.showsCameraControls = YES;

    overlayView = [[UIView alloc] initWithFrame:self.view.frame];

    // Start/ Stop fake button
    UIView *ssView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width / 2 - 35, self.view.frame.size.height - 71, 70, 70)];
    [ssView setUserInteractionEnabled:YES];
    // Background color below is only there to make sure myt pseudo-button overlaps native Start/Stop button
    [ssView setBackgroundColor:[UIColor colorWithRed:0 green:1 blue:0 alpha:0.5f]];

   UITapGestureRecognizer *t = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
   [ssView addGestureRecognizer:t];

   [overlayView addSubview:ssView];

   // My own progress bar
   UIProgressView *p = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
   [p setTintColor:[UIColor redColor]];
   [p setCenter:CGPointMake(30, 130)];
   [p setTransform:CGAffineTransformMakeRotation( M_PI / 2 )];
   [p setProgress:0];

   [overlayView addSubview:p];

   pickerController.cameraOverlayView = overlayView;

}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    // Cancel button tapped
    [picker dismissViewControllerAnimated:YES completion:nil];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

    NSLog(@"Got image : %@", info);
    [picker dismissViewControllerAnimated:YES completion:nil];

    // Do something with video captured
}

-(void)tapped:(id)sender {

    if (isRecording) {
        [pickerController stopVideoCapture];
        NSLog(@"Video capturing stopped...");
        // add your business logic here ie stop updating progress bar etc...
        [pickerController.cameraOverlayView setHidden:YES];
        isRecording = NO;
        return;
    }

    if ([pickerController startVideoCapture]) {
        NSLog(@"Video capturing started...");
        // add your business logic here ie start updating progress bar etc...
        isRecording = YES;
    }

}

- (IBAction)openCamera:(id)sender {
    [pickerController.cameraOverlayView setHidden:NO];
    [self presentViewController:pickerController animated:YES completion:nil];    
}
@end

您可能我注意到一旦视频捕捉停止我就会隐藏cameraOverlayView。

[pickerController.cameraOverlayView setHidden:YES];

这是为了允许“重新拍摄/播放和使用”本机控件在录制视频后正常工作。

In a perfect world you'd want Apple to provide just a couple of delegates that would do that. For example :

  • (void)imagePickerControllerDidStartVideoCapturing:(UIImagePickerController *)picker
  • (void)imagePickerControllerDidStopVideoCapturing:(UIImagePickerController *)picker

Reality however (as per apple documentation) is that :

  • Protocol for UIImagePickerController is too basic to do that
  • This class is intended to be used as-is and does not support subclassing
  • The view hierarchy for this class is private and must not be modified

Documentation also states : "You can assign a custom view to the cameraOverlayView property and use that view to present additional information or manage the interactions between the camera interface and your code".

In my application I needed to present "UIProgressView" to indicate how much longer the video could be recorded. In order to accomplish that I needed to be able to detect the moment video capturing started.

I didn't want to disable native camera controls because they are cool and I'm lazy so that I didn't want to spend much time reinventing the wheel. Simply all I needed was to capture the fact that a big RED button was tapped to either start or stop recording.

My solution was to "cover" original Start/Stop recording button with a custom view and enable user interaction for that view as follow :

overlayView = [[UIView alloc] initWithFrame:self.view.frame];

// Start/ Stop fake button
UIView *ssView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width / 2 - 35, self.view.frame.size.height - 71, 70, 70)];
[ssView setUserInteractionEnabled:YES];

// Background color below is only there to make sure my pseudo-button overlaps native Start/Stop button. Comment out the line below to leave it transparent
[ssView setBackgroundColor:[UIColor colorWithRed:0 green:1 blue:0 alpha:0.5f]];

UITapGestureRecognizer *t = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
[ssView addGestureRecognizer:t];

[overlayView addSubview:ssView];  

// My own progress bar
UIProgressView *p = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
[p setTintColor:[UIColor redColor]];
[p setCenter:CGPointMake(30, 130)];
[p setTransform:CGAffineTransformMakeRotation( M_PI / 2 )];
[p setProgress:0];

[overlayView addSubview:p];

pickerController.cameraOverlayView = overlayView;

I then defined event handler for a tap as follow :

-(void)tapped:(id)sender {

    if (isRecording) {
        [pickerController stopVideoCapture];
        NSLog(@"Video capturing stopped...");
        // add your business logic here ie stop updating progress bar etc...
        [pickerController.cameraOverlayView setHidden:YES];
        isRecording = NO;
        return;
    }

    if ([pickerController startVideoCapture]) {
        NSLog(@"Video capturing started...");
        // add your business logic here ie start updating progress bar etc...
        isRecording = YES;
    }

}

Full code of the interface file :

#import <UIKit/UIKit.h>
#import <MobileCoreServices/MobileCoreServices.h>

@interface ViewController : UIViewController <UIImagePickerControllerDelegate>
- (IBAction)openCamera:(id)sender;

@end

Implementation file :

#import "ViewController.h"

@interface ViewController () {
    UIImagePickerController *pickerController;
    UIView* overlayView;
    BOOL isRecording;
}

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    isRecording = NO;

    pickerController = [[UIImagePickerController alloc] init];
    pickerController.delegate = self;
    pickerController.allowsEditing = NO;
    pickerController.videoMaximumDuration = 30.0f;
    pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
    pickerController.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil];

    // I want default controls be available here...
    pickerController.showsCameraControls = YES;

    overlayView = [[UIView alloc] initWithFrame:self.view.frame];

    // Start/ Stop fake button
    UIView *ssView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width / 2 - 35, self.view.frame.size.height - 71, 70, 70)];
    [ssView setUserInteractionEnabled:YES];
    // Background color below is only there to make sure myt pseudo-button overlaps native Start/Stop button
    [ssView setBackgroundColor:[UIColor colorWithRed:0 green:1 blue:0 alpha:0.5f]];

   UITapGestureRecognizer *t = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
   [ssView addGestureRecognizer:t];

   [overlayView addSubview:ssView];

   // My own progress bar
   UIProgressView *p = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
   [p setTintColor:[UIColor redColor]];
   [p setCenter:CGPointMake(30, 130)];
   [p setTransform:CGAffineTransformMakeRotation( M_PI / 2 )];
   [p setProgress:0];

   [overlayView addSubview:p];

   pickerController.cameraOverlayView = overlayView;

}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    // Cancel button tapped
    [picker dismissViewControllerAnimated:YES completion:nil];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

    NSLog(@"Got image : %@", info);
    [picker dismissViewControllerAnimated:YES completion:nil];

    // Do something with video captured
}

-(void)tapped:(id)sender {

    if (isRecording) {
        [pickerController stopVideoCapture];
        NSLog(@"Video capturing stopped...");
        // add your business logic here ie stop updating progress bar etc...
        [pickerController.cameraOverlayView setHidden:YES];
        isRecording = NO;
        return;
    }

    if ([pickerController startVideoCapture]) {
        NSLog(@"Video capturing started...");
        // add your business logic here ie start updating progress bar etc...
        isRecording = YES;
    }

}

- (IBAction)openCamera:(id)sender {
    [pickerController.cameraOverlayView setHidden:NO];
    [self presentViewController:pickerController animated:YES completion:nil];    
}
@end

You might have noticed that I'm hiding cameraOverlayView once video capturing is stopped.

[pickerController.cameraOverlayView setHidden:YES];

This is to allow "Retake / Play and Use" native controls to work properly after video has been recorded.

明天过后 2024-10-23 04:49:03

当用户点击按钮时,您不会收到通知,但您可以提供自己的记录按钮:将图像选择器设置为隐藏其标准控件 (showsCameraControls) 并提供自定义叠加视图 (cameraOverlayView)。在该叠加视图中,放置一个连接到目标/操作的自定义按钮,并在操作方法中调用 -startVideoCapture

You don't get notified when the user taps the button but you can provide your own record button: set the image picker to hide its standard controls (showsCameraControls) and provide a custom overlay view (cameraOverlayView). In that overlay view, place a custom button that you connect to a target/action, and in the action method you call -startVideoCapture.

桜花祭 2024-10-23 04:49:03

好的。所以我很确定我想要实现的目标是不可能的。我将使用 AVFoundation 作为后端为视频重新创建标准 UIImagePickerController 接口。希望一旦完成我会将其发布到 github 或其他地方。

Okay. So I'm pretty sure what I want to achieve is just not possible. I'm going to just re-create the standard UIImagePickerController interface for videos using AVFoundation as the backend. Hopefully once it is done I'll post it on github or something.

z祗昰~ 2024-10-23 04:49:03

我通过使用自定义叠加视图创建了您正在寻找的相同效果。

您需要使用 UIVideoEditorController 实例创建一个模式窗口,其 videoPath 属性是 userInfo 中的 UIImagePickerControllerMediaURL 键您应该处理的 imagePickerController:didFinishPickingMediaWithInfo: 方法。

华泰

I created the same effect you're looking for by using a custom overlay view.

You need to create a modal window with an instance of UIVideoEditorController who's videoPath property is the UIImagePickerControllerMediaURL key in userInfo from the imagePickerController:didFinishPickingMediaWithInfo: method you should be handling.

HTH

别闹i 2024-10-23 04:49:03

对于其他人来说,如果您在 UIImagePickerController 上使用自定义叠加视图,则可以完成此操作。只需将所需的所有控件添加到视图中,然后将该父视图设置为属性 cameraOverlayView 即可。

For anyone else, this can be done if you use a custom overlay view on the UIImagePickerController. Just add all the controls you want to a view and then set that parent view to the property cameraOverlayView.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文