diff --git a/Camera.ios.js b/Camera.ios.js index 3e6a4e0..ec14aed 100644 --- a/Camera.ios.js +++ b/Camera.ios.js @@ -51,7 +51,10 @@ var Camera = React.createClass({ torchMode: PropTypes.oneOfType([ PropTypes.string, PropTypes.number - ]) + ]), + defaultTouchToFocus: PropTypes.bool, + onFocusChanged: PropTypes.func, + onZoomChanged: PropTypes.func }, mixins: [NativeMethodsMixin], @@ -205,7 +208,10 @@ var RCTCamera = createReactNativeComponentClass({ type: true, orientation: true, flashMode: true, - torchMode: true + torchMode: true, + onFocusChanged: true, + onZoomChanged: true, + defaultTouchToFocus: true }), uiViewClassName: 'RCTCamera', }); diff --git a/RCTCamera.h b/RCTCamera.h index edeaf27..6d92743 100644 --- a/RCTCamera.h +++ b/RCTCamera.h @@ -7,9 +7,9 @@ @interface RCTCamera : UIView @property (nonatomic) RCTCameraManager *manager; +@property (nonatomic) RCTBridge *bridge; @property (nonatomic) RCTCameraFocusSquare *camFocus; -@property (nonatomic) BOOL multipleTouches; -- (id)initWithManager:(RCTCameraManager*)manager; +- (id)initWithManager:(RCTCameraManager*)manager bridge:(RCTBridge *)bridge; @end diff --git a/RCTCamera.m b/RCTCamera.m index 891b31d..336f9bb 100644 --- a/RCTCamera.m +++ b/RCTCamera.m @@ -3,11 +3,20 @@ #import "RCTCameraManager.h" #import "RCTLog.h" #import "RCTUtils.h" +#import "RCTEventDispatcher.h" + +#import "UIView+React.h" #import #import "CameraFocusSquare.h" @implementation RCTCamera +{ + BOOL _multipleTouches; + BOOL _onFocusChanged; + BOOL _defaultTouchToFocus; + BOOL _onZoomChanged; +} - (void)setAspect:(NSInteger)aspect { @@ -60,16 +69,41 @@ [self.manager changeTorchMode:torchMode]; } -- (id)initWithManager:(RCTCameraManager*)manager +- (void)setOnFocusChanged:(BOOL)enabled +{ + if (_onFocusChanged != enabled) { + _onFocusChanged = enabled; + } +} + +- (void)setDefaultTouchToFocus:(BOOL)enabled +{ + if (_defaultTouchToFocus != enabled) { + _defaultTouchToFocus = enabled; + } +} + +- (void)setOnZoomChanged:(BOOL)enabled +{ + if (_onZoomChanged != enabled) { + _onZoomChanged = enabled; + } +} + +- (id)initWithManager:(RCTCameraManager*)manager bridge:(RCTBridge *)bridge { if ((self = [super init])) { self.manager = manager; + self.bridge = bridge; UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchToZoomRecognizer:)]; [self addGestureRecognizer:pinchGesture]; [self.manager initializeCaptureSessionInput:AVMediaTypeVideo]; [self.manager startSession]; - self.multipleTouches = NO; + _multipleTouches = NO; + _onFocusChanged = NO; + _defaultTouchToFocus = YES; + _onZoomChanged = NO; } return self; } @@ -111,17 +145,19 @@ { // Update the touch state. if ([[event touchesForView:self] count] > 1) { - self.multipleTouches = YES; + _multipleTouches = YES; } } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + if (!_onFocusChanged) return; + BOOL allTouchesEnded = ([touches count] == [[event touchesForView:self] count]); // Do not conflict with zooming and etc. - if (allTouchesEnded && !self.multipleTouches) { + if (allTouchesEnded && !_multipleTouches) { UITouch *touch = [[event allTouches] anyObject]; CGPoint touchPoint = [touch locationInView:touch.view]; // Focus camera on this point @@ -131,28 +167,41 @@ { [self.camFocus removeFromSuperview]; } - // Show animated rectangle on the touched area - self.camFocus = [[RCTCameraFocusSquare alloc]initWithFrame:CGRectMake(touchPoint.x-40, touchPoint.y-40, 80, 80)]; - [self.camFocus setBackgroundColor:[UIColor clearColor]]; - [self addSubview:self.camFocus]; - [self.camFocus setNeedsDisplay]; + NSDictionary *event = @{ + @"target": self.reactTag, + @"touchPoint": @{ + @"x": [NSNumber numberWithDouble:touchPoint.x], + @"y": [NSNumber numberWithDouble:touchPoint.y] + } + }; + [self.bridge.eventDispatcher sendInputEventWithName:@"focusChanged" body:event]; - [UIView beginAnimations:nil context:NULL]; - [UIView setAnimationDuration:1.0]; - [self.camFocus setAlpha:0.0]; - [UIView commitAnimations]; + // Show animated rectangle on the touched area + if (_defaultTouchToFocus) { + self.camFocus = [[RCTCameraFocusSquare alloc]initWithFrame:CGRectMake(touchPoint.x-40, touchPoint.y-40, 80, 80)]; + [self.camFocus setBackgroundColor:[UIColor clearColor]]; + [self addSubview:self.camFocus]; + [self.camFocus setNeedsDisplay]; + + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationDuration:1.0]; + [self.camFocus setAlpha:0.0]; + [UIView commitAnimations]; + } } if (allTouchesEnded) { - self.multipleTouches = NO; + _multipleTouches = NO; } } -(void) handlePinchToZoomRecognizer:(UIPinchGestureRecognizer*)pinchRecognizer { + if (!_onZoomChanged) return; + if (pinchRecognizer.state == UIGestureRecognizerStateChanged) { - [self.manager zoom:pinchRecognizer.velocity]; + [self.manager zoom:pinchRecognizer.velocity reactTag:self.reactTag]; } } diff --git a/RCTCameraManager.h b/RCTCameraManager.h index bcb7bb7..9bf9c7a 100644 --- a/RCTCameraManager.h +++ b/RCTCameraManager.h @@ -73,7 +73,7 @@ typedef NS_ENUM(NSInteger, RCTCameraTorchMode) { - (void)startSession; - (void)stopSession; - (void)focusAtThePoint:(CGPoint) atPoint; -- (void)zoom:(CGFloat)velocity; +- (void)zoom:(CGFloat)velocity reactTag:(NSNumber *)reactTag; @end diff --git a/RCTCameraManager.m b/RCTCameraManager.m index b4759b6..ae6f350 100644 --- a/RCTCameraManager.m +++ b/RCTCameraManager.m @@ -16,7 +16,7 @@ RCT_EXPORT_MODULE(); - (UIView *)view { - return [[RCTCamera alloc] initWithManager:self]; + return [[RCTCamera alloc] initWithManager:self bridge:self.bridge]; } RCT_EXPORT_VIEW_PROPERTY(aspect, NSInteger); @@ -93,6 +93,18 @@ RCT_EXPORT_VIEW_PROPERTY(torchMode, NSInteger); ]; } +RCT_EXPORT_VIEW_PROPERTY(defaultTouchToFocus, BOOL); +RCT_EXPORT_VIEW_PROPERTY(onFocusChanged, BOOL) +RCT_EXPORT_VIEW_PROPERTY(onZoomChanged, BOOL) + +- (NSDictionary *)customDirectEventTypes +{ + return @{ + @"focusChanged": @{ @"registrationName": @"onFocusChanged" }, + @"zoomChanged": @{ @"registrationName": @"onZoomChanged" }, + }; +} + - (id)init { if ((self = [super init])) { @@ -688,12 +700,19 @@ didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL } } -- (void) zoom:(CGFloat)velocity { +- (void) zoom:(CGFloat)velocity reactTag:(NSNumber *)reactTag{ const CGFloat pinchVelocityDividerFactor = 20.0f; // TODO: calibrate or make this component's property NSError *error = nil; AVCaptureDevice *device = [[self videoCaptureDeviceInput] device]; if ([device lockForConfiguration:&error]) { CGFloat zoomFactor = device.videoZoomFactor + atan(velocity / pinchVelocityDividerFactor); + NSDictionary *event = @{ + @"target": reactTag, + @"zoomFactor": [NSNumber numberWithDouble:zoomFactor], + @"velocity": [NSNumber numberWithDouble:velocity] + }; + [self.bridge.eventDispatcher sendInputEventWithName:@"zoomChanged" body:event]; + device.videoZoomFactor = zoomFactor >= 1.0f ? zoomFactor : 1.0f; [device unlockForConfiguration]; } else {