回答
你是对的:代表没有收到关于何时发生视频捕获的任何信息。简单的解决方案是简单地滚动您自己的相机控件 - 将showsCameraControls
属性设置为NO
,并使用cameraOverlayView
属性在自定义视图中提供您自己的控件 - 并让您的“捕捉”按钮调用图像选择器控制器的-startVideoCapture
和-stopVideoCapture
方法提供您需要的任何通知给应用程序的其他部分。
根据IOS API,方法 “startVideoCapture” 给出了布尔返回值
是意味着它记录
没有指下列条件之一:
- 电影捕获已在进行中
- 该设备不支持电影
- 捕获该设备是磁盘空间
[参考:http://developer.apple.com/library/ios/#documentation/uikit/reference/UIImagePickerController_Class/UIImagePickerController/UIImagePickerController.html]
所以只要'startRecording'返回一个是,你几乎可以肯定地说它是录音。当然,要检查这一点,你可以随时用NSTimer手动定义你自己的回呼(虽然以前有一个热门辩论关于其准确性的高调)。
在一个完美的世界中,你希望苹果只提供一个几位代表会这样做。例如:
- (无效)imagePickerControllerDidStartVideoCapturing:(的UIImagePickerController *)选择器
- (无效)imagePickerControllerDidStopVideoCapturing:(的UIImagePickerController *)选择器
现实然而(按照苹果文档)是:
- 针对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
Implementati on 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
您可能已经注意到,一旦视频捕捉停止后,我隐藏了cameraOverlayView。
[pickerController.cameraOverlayView setHidden:YES];
这是为了允许在录制视频后“重播/播放和使用”原生控件正常工作。
真棒,你有一个按钮的图像? – Sasho 2014-05-01 09:20:12
这是一个swift 3 UIImagePickerController类,它只允许用户在相机处于横向时捕捉视频。
当您创建的UIImagePickerController:
var imagePicker = CameraVideo_ViewController()
你需要有这将委托作为得好:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
self.imagePicker.isInFinalScreen = false
}
这是类。我真的没有时间整理它,它真的很混乱......我创建了这个类,通过尝试我所能做的一切,而无需删除默认控件。使用了一堆黑客,因此在删除变量时要非常小心,因为即使它们看起来没有用处,它们大多数都会计数。我会尝试重新发布一个更清晰的版本,我可以找到一些时间,但在那之前如果有人可以转贴一个更清洁,更新手我/我们将不胜感激。
import UIKit
import AVFoundation;
class CameraVideo_ViewController: UIImagePickerController {
var viewMain:UIView!
var lastOrientationWasLandscape:UIDeviceOrientation?
var isForLibrary:Bool! = false
var parentController:UIViewController!
override func viewDidAppear(_ animated: Bool) {
if isForLibrary == true {
return
}
let orientation = UIDevice.current.orientation
if orientation == .landscapeLeft || orientation == .landscapeRight {
lastOrientationWasLandscape = orientation
}
if (self.isInFinalScreen == true){
self.recordBut.frame = CGRect(x: self.view.frame.size.width - 70 - 16, y: self.view.frame.size.height/2 - 35, width: 70, height: 70)
self.isInFinalScreen = false
}
recordBut.alpha = 1
recordBut.isUserInteractionEnabled = true
retakeBut.alpha = 1
retakeBut.isUserInteractionEnabled = true
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
NotificationCenter.default.addObserver(self, selector: #selector(orientationChanged(_:)), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
let notif = Notification.init(name: NSNotification.Name.UIDeviceOrientationDidChange)
orientationChanged(notif)
}
override func viewWillDisappear(_ animated: Bool) {
viewMain.alpha = 0
viewMain.isUserInteractionEnabled = false
lastOrientationWasLandscape = nil
recordBut.alpha = 0
recordBut.isUserInteractionEnabled = false
retakeBut.alpha = 0
retakeBut.isUserInteractionEnabled = false
self.viewMain.alpha = 0
self.viewMain.isUserInteractionEnabled = false
isInFinalScreenBool = false
recordedThisSession = false
if isForLibrary == true {
return
}
print("hidingCameraView")
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
UIDevice.current.endGeneratingDeviceOrientationNotifications()
}
override func viewDidLoad() {
super.viewDidLoad()
if isForLibrary == true {
return
}
viewMain = UIView()
viewMain.frame = CGRect(x: view.frame.minX, y: view.frame.minY, width: view.frame.width, height: view.frame.height)
viewMain.backgroundColor = UIColor.clear
let viewBg = UIView()
viewBg.frame = CGRect(x: view.frame.minX, y: view.frame.minY, width: view.frame.width, height: view.frame.height)
viewBg.backgroundColor = UIColor.black
viewBg.alpha = 0.5
let viewAlertBg = UIView()
viewAlertBg.frame = CGRect(x: view.frame.width/2 - 250/2, y: view.frame.height/2 - 100/2 - 25, width: 250, height: 100)
viewAlertBg.backgroundColor = UIColor.white
viewAlertBg.alpha = 1
viewAlertBg.clipsToBounds = true;
var path = UIBezierPath(roundedRect:viewAlertBg.bounds,
byRoundingCorners:[.topLeft, .topRight],
cornerRadii: CGSize(width: 25, height: 25))
var maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
viewAlertBg.layer.mask = maskLayer
let viewAlertBgUnderline = UIView()
viewAlertBgUnderline.frame = CGRect(x: view.frame.width/2 - 250/2, y: viewAlertBg.frame.maxY, width: 250, height: 1)
viewAlertBgUnderline.backgroundColor = UIColor.lightGray
viewAlertBgUnderline.alpha = 1
viewAlertBgUnderline.clipsToBounds = true;
let viewAlertCancelBut = UIButton()
viewAlertCancelBut.frame = CGRect(x: view.frame.width/2 - 250/2, y: viewAlertBgUnderline.frame.maxY, width: 250, height: 50)
viewAlertCancelBut.backgroundColor = UIColor.white
viewAlertCancelBut.setTitle("Back", for: .normal)
viewAlertCancelBut.setTitleColor(UIColor.blue, for: .normal)
path = UIBezierPath(roundedRect:viewAlertCancelBut.bounds,
byRoundingCorners:[.bottomLeft, .bottomRight],
cornerRadii: CGSize(width: 25, height: 25))
maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
viewAlertCancelBut.layer.mask = maskLayer
viewAlertCancelBut.addTarget(self, action: #selector(onBack(_:)), for: .touchUpInside)
let alertLabel = UILabel()
alertLabel.numberOfLines = 4
alertLabel.frame = CGRect(x: 16, y: 16, width: 250 - 32, height: 100 - 32)
alertLabel.textAlignment = NSTextAlignment.center
alertLabel.adjustsFontSizeToFitWidth = true
alertLabel.font = UIFont.systemFont(ofSize: 12)
alertLabel.backgroundColor = UIColor.clear
alertLabel.textColor = UIColor.black
let boldText = "The video must be recorded in landscape mode.\n"
let normalText = "Please hold your device in a horizontal position!"
let attrs = [NSFontAttributeName : UIFont.boldSystemFont(ofSize: 13)]
let boldString = NSMutableAttributedString(string:boldText, attributes:attrs)
let attributedString = NSMutableAttributedString(string:"")
attributedString.append(boldString)
attributedString.append(NSMutableAttributedString(string:normalText, attributes:nil))
alertLabel.attributedText = attributedString
viewAlertBg.addSubview(alertLabel)
viewMain.addSubview(viewBg)
viewMain.addSubview(viewAlertCancelBut)
viewMain.addSubview(viewAlertBg)
viewMain.addSubview(viewAlertBgUnderline)
viewMain.alpha = 0
viewMain.isUserInteractionEnabled = false
// Start/ Stop fake button
recordBut = UIButton()
if (UIDevice.current.userInterfaceIdiom == .phone){
recordBut.frame = CGRect(x: self.view.frame.size.width/2 - 35, y: self.view.frame.size.height - 70 - 2, width: 70, height: 70)
}else{
recordBut.frame = CGRect(x: self.view.frame.size.height - 70 - 16, y: self.view.frame.size.width/2 - 35, width: 70, height: 70)
}
recordBut.setTitle("", for: .normal)
recordBut.setTitleColor(UIColor.blue, for: .normal)
recordBut.isUserInteractionEnabled = true
recordBut.backgroundColor = UIColor(red: 0, green: 1, blue: 0, alpha: 0.5)
recordBut.addTarget(self, action: #selector(tapped(_:)), for: .touchUpInside)
self.view.addSubview(recordBut)
retakeBut = UIButton()
if (UIDevice.current.userInterfaceIdiom == .phone){
retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70)
}else{
retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.width - 70, width: 80, height: 70)
}
retakeBut.setTitle("", for: .normal)
retakeBut.setTitleColor(UIColor.blue, for: .normal)
retakeBut.isUserInteractionEnabled = true
retakeBut.backgroundColor = UIColor(red: 0, green: 1, blue: 0, alpha: 0.5)
retakeBut.addTarget(self, action: #selector(retake(_:)), for: .touchUpInside)
self.view.addSubview(retakeBut)
self.view.addSubview(viewMain)
}
override func viewDidLayoutSubviews() {
if isForLibrary == true {
return
}
self.adjustViews(for: UIDevice.current.orientation)
}
var t:UITapGestureRecognizer!
var recordBut:UIButton!
var retakeBut:UIButton!
var isInFinalScreen:Bool = false
var isRecording:Bool = false
var isInFinalScreenBool:Bool = false
var recordedThisSession:Bool = false
func tapped(_ sender:UIButton){
if (isRecording == false && self.startVideoCapture()){
recordedThisSession = true
isRecording = true
retakeBut.alpha = 0
retakeBut.isUserInteractionEnabled = false
}else{
retakeBut.alpha = 1
retakeBut.isUserInteractionEnabled = true
recordBut.alpha = 0
recordBut.isUserInteractionEnabled = false
self.stopVideoCapture()
isRecording = false
if (UIDevice.current.orientation != .portrait){
self.adjustViews(for: UIDevice.current.orientation)
}
isInFinalScreen = true
return
}
}
func retake(_ sender:UIButton){
if (recordedThisSession == false){
onBack(sender)
}
self.dismiss(animated: true, completion: {
self.parentController.present((self.parentController as! AddVideo_ViewController).imagePicker, animated: true, completion: {
})
})
}
func onBack(_ sender:UIButton){
self.isInFinalScreen = false
self.dismiss(animated: true, completion: {
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func orientationChanged(_ notification: Notification) {
self.adjustViews(for: UIDevice.current.orientation)
}
func adjustViews(for orient: UIDeviceOrientation) {
var orientation = orient
if (orientation.isLandscape == true) || (orientation.isFlat && lastOrientationWasLandscape?.isPortrait == false) {
print(".....landscape.....")
if (UIDevice.current.userInterfaceIdiom == .pad){
self.recordBut.frame = CGRect(x: self.view.frame.size.width - 70 - 16, y: self.view.frame.size.height/2 - 35, width: 70, height: 70)
self.retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70)
}else{
recordBut.frame = CGRect(x: self.view.frame.size.width/2 - 35, y: self.view.frame.size.height - 70 - 2, width: 70, height: 70)
retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70)
}
if (recordedThisSession == false){
if (UIDevice.current.userInterfaceIdiom == .pad){
self.retakeBut.frame = CGRect(x: self.view.frame.size.width - 100, y: self.view.frame.size.height - 70, width: 100, height: 70)
}else{
retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70)
}
}
if (self.isInFinalScreenBool == true){
return
}
if (self.isInFinalScreen == true){
self.isInFinalScreenBool = !isInFinalScreenBool
self.isInFinalScreen = false
return
}
if (self.isRecording){
return
}
self.viewMain.alpha = 0
self.viewMain.isUserInteractionEnabled = false
self.lastOrientationWasLandscape = orientation
}
else {
print(".....portrait.....")
self.lastOrientationWasLandscape = UIDeviceOrientation(rawValue: UIDeviceOrientation.portrait.rawValue)
if (UIDevice.current.userInterfaceIdiom == .pad){
self.recordBut.frame = CGRect(x: self.view.frame.size.width - 70 - 16, y: self.view.frame.size.height/2 - 35, width: 70, height: 70)
self.retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70)
}else{
recordBut.frame = CGRect(x: self.view.frame.size.width/2 - 35, y: self.view.frame.size.height - 70 - 2, width: 70, height: 70)
retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70)
}
if (recordedThisSession == false){
if (UIDevice.current.userInterfaceIdiom == .pad){
self.retakeBut.frame = CGRect(x: self.view.frame.size.width - 100, y: self.view.frame.size.height - 70, width: 100, height: 70)
}else{
retakeBut.frame = CGRect(x: 0, y: self.view.frame.size.height - 70, width: 80, height: 70)
}
}
if (self.isInFinalScreenBool == true){
return
}
if (self.isInFinalScreen){
return
}
if (self.isRecording){
return
}
self.viewMain.alpha = 1
self.viewMain.isUserInteractionEnabled = true
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
祝你好运!
- 1. 检测录像开始
- 2. jwplayer - 检测开始
- 3. Iphone。检测声音时如何开始录音,检测到静音时停止录音
- 4. 如何检测ajax调用的开始?
- 5. 如何检测用户何时开始在浏览器中下载?
- 6. 如何检测用户何时开始在浏览器中下载文件?
- 7. 如何检测Windows开始菜单/开始屏幕何时打开?
- 8. 如何检测Windows 7开始菜单何时打开
- 9. Java Web开始 - 如何检测应用程序何时关闭?
- 10. jQuery可能检测用户在Textarea时何时离开?
- 11. 检测音频何时开始播放其他应用程序
- 12. 开始碰撞检测
- 13. 如何检测用户的手指何时离开元素?
- 14. 如何检测用户何时打开OS X通知中心?
- 15. 如何检测用户何时离开EditText?
- 16. 如何检测用户何时切换到登录屏幕?
- 17. 在Meteor中,如何检测新用户何时登录?
- 18. 如何检测datagridview开始填充
- 19. 如何检测活动开始
- 20. 如何检测流程的开始?
- 21. 自动开始录像
- 22. 如何检测UIWebView何时开始选择文本?
- 23. 如何检测CSS动画何时以JavaScript开始和结束?
- 24. 如何检测VideoView何时开始播放(Android)?
- 25. 如何检测Entity Framework中的编辑何时开始?
- 26. 如何检测iframe何时开始加载另一个页面?
- 27. 如何检测何时在Android键盘上按“开始”
- 28. 如何检测AVPlayer何时开始/停止播放
- 29. 如何检测用户离开MMC FormView的时间?
- 30. 检测用户何时离开Page_Load事件的页面
我喜欢这种方法.. – Obaid 2011-06-18 04:07:21
那么你可以在哪里播放和重播视频呢?你如何创建这些屏幕? – PoolHallJunkie 2017-01-09 11:21:11