From 7f4eb47f81e5e915fe4058e2dc9f1d83c9a60c75 Mon Sep 17 00:00:00 2001 From: Horcrux Date: Sat, 6 Aug 2016 21:37:58 +0800 Subject: [PATCH] fix touch events within the elements which are nested in G --- Example/examples/TouchEvents.js | 39 +++++++++++++++++++-------------- elements/Svg.js | 30 ++++++++++++------------- ios/Elements/RNSVGGroup.h | 3 --- ios/Elements/RNSVGGroup.m | 30 +++++++++++++++++-------- ios/Elements/RNSVGImage.m | 9 ++------ ios/Elements/RNSVGPath.m | 26 +++++++++++++--------- ios/RNSVGNode.h | 3 ++- ios/RNSVGNode.m | 16 ++++++++------ ios/RNSVGRenderable.h | 2 +- ios/RNSVGRenderable.m | 25 ++++++++++++++++----- ios/RNSVGViewBox.m | 6 ++--- ios/Shapes/RNSVGCircle.m | 6 ----- ios/Shapes/RNSVGEllipse.m | 6 ----- ios/Shapes/RNSVGLine.m | 6 ----- ios/Shapes/RNSVGRect.m | 6 ----- ios/Text/RNSVGText.m | 7 +----- ios/Utils/RCTConvert+RNSVG.m | 24 ++++++++++---------- 17 files changed, 123 insertions(+), 121 deletions(-) diff --git a/Example/examples/TouchEvents.js b/Example/examples/TouchEvents.js index 44e03121..15527cb8 100644 --- a/Example/examples/TouchEvents.js +++ b/Example/examples/TouchEvents.js @@ -56,18 +56,23 @@ class HoverExample extends Component { render () { return - + + + + + ; } } @@ -82,10 +87,12 @@ class GroupExample extends Component { viewBox="0 0 240 240" > - alert('Pressed')}> - - - H + + + alert('Pressed')}/> + + H + ; diff --git a/elements/Svg.js b/elements/Svg.js index 5e6e5d10..a3a0d217 100644 --- a/elements/Svg.js +++ b/elements/Svg.js @@ -73,22 +73,20 @@ class Svg extends Component{ const nativeProps = _.omit(props, ['width', 'height', 'viewBox', 'preserveAspectRatio', 'opacity']); - return ( - {this.root = ele;}} - style={[ - styles.svg, - props.style, - !isNaN(opacity) && { - opacity - }, - dimensions - ]} - > - {content} - - ); + return {this.root = ele;}} + style={[ + styles.svg, + props.style, + !isNaN(opacity) && { + opacity + }, + dimensions + ]} + > + {content} + ; } } diff --git a/ios/Elements/RNSVGGroup.h b/ios/Elements/RNSVGGroup.h index 12b035d5..d111da22 100644 --- a/ios/Elements/RNSVGGroup.h +++ b/ios/Elements/RNSVGGroup.h @@ -14,7 +14,4 @@ #import "RNSVGRenderable.h" @interface RNSVGGroup : RNSVGRenderable - -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; - @end diff --git a/ios/Elements/RNSVGGroup.m b/ios/Elements/RNSVGGroup.m index 6b62b490..64d46845 100644 --- a/ios/Elements/RNSVGGroup.m +++ b/ios/Elements/RNSVGGroup.m @@ -14,14 +14,14 @@ { RNSVGSvgView* svg = [self getSvgView]; [self clip:context]; - + for (RNSVGNode *node in self.subviews) { if ([node isKindOfClass:[RNSVGNode class]]) { [node mergeProperties:self mergeList:self.propList inherited:YES]; [node renderTo:context]; - + if (node.responsible && !svg.responsible) { - self.responsible = YES; + svg.responsible = YES; } } } @@ -32,21 +32,33 @@ CGMutablePathRef path = CGPathCreateMutable(); for (RNSVGNode *node in self.subviews) { if ([node isKindOfClass:[RNSVGNode class]]) { - CGAffineTransform transform = node.transform; + CGAffineTransform transform = node.matrix; CGPathAddPath(path, &transform, [node getPath:context]); } } return (CGPathRef)CFAutorelease(path); } -// hitTest delagate -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event withTransform:(CGAffineTransform)transform { + CGAffineTransform matrix = CGAffineTransformConcat(self.matrix, transform); + for (RNSVGNode *node in [self.subviews reverseObjectEnumerator]) { if ([node isKindOfClass:[RNSVGNode class]]) { - UIView *view = [node hitTest: point withEvent:event]; + if (event) { + node.active = NO; + } + + if (node.active) { + return node; + } + + + UIView *view = [node hitTest: point withEvent:event withTransform:matrix]; + if (view) { - if (node.responsible || node != view) { + node.active = YES; + if (node.responsible || (node != view)) { return view; } else { return self; @@ -63,7 +75,7 @@ RNSVGSvgView* svg = [self getSvgView]; [svg defineTemplate:self templateRef:self.name]; } - + for (RNSVGNode *node in self.subviews) { if ([node isKindOfClass:[RNSVGNode class]]) { [node saveDefinition]; diff --git a/ios/Elements/RNSVGImage.m b/ios/Elements/RNSVGImage.m index 3b8eaf00..7122bffc 100644 --- a/ios/Elements/RNSVGImage.m +++ b/ios/Elements/RNSVGImage.m @@ -71,10 +71,7 @@ { CGRect rect = [self getRect:context]; // add hit area - self.hitArea = CGPathCreateMutable(); - CGPathRef path = CGPathCreateWithRect(rect, nil); - CGPathAddPath(self.hitArea, nil, path); - CGPathRelease(path); + self.hitArea = CGPathCreateWithRect(rect, nil); [self clip:context]; CGContextSaveGState(context); @@ -97,9 +94,7 @@ - (CGPathRef)getPath:(CGContextRef)context { - CGMutablePathRef path = CGPathCreateMutable(); - CGPathAddRect(path, nil, [self getRect:context]); - return (CGPathRef)CFAutorelease(path); + return CGPathCreateWithRect([self getRect:context], nil); } @end diff --git a/ios/Elements/RNSVGPath.m b/ios/Elements/RNSVGPath.m index 3b14b7be..2392afdc 100644 --- a/ios/Elements/RNSVGPath.m +++ b/ios/Elements/RNSVGPath.m @@ -15,6 +15,7 @@ if (d == _d) { return; } + [self invalidate]; CGPathRelease(_d); _d = CGPathRetain(d); @@ -27,20 +28,25 @@ - (void)renderLayerTo:(CGContextRef)context { - if ((!self.fill && !self.stroke) || !self.d) { + CGPathRef path = [self getPath:context]; + if ((!self.fill && !self.stroke) || !path) { return; } // Add path to hitArea - self.hitArea = CGPathCreateMutableCopy(_d); - + CGMutablePathRef hitArea = CGPathCreateMutableCopy(path); if (self.stroke) { // Add stroke to hitArea - CGPathRef strokePath = CGPathCreateCopyByStrokingPath(_d, nil, self.strokeWidth, self.strokeLinecap, self.strokeLinejoin, self.strokeMiterlimit); - CGPathAddPath(self.hitArea, nil, strokePath); + CGPathRef strokePath = CGPathCreateCopyByStrokingPath(hitArea, nil, self.strokeWidth, self.strokeLinecap, self.strokeLinejoin, self.strokeMiterlimit); + CGPathAddPath(hitArea, nil, strokePath); CGPathRelease(strokePath); } + CGAffineTransform transform = self.matrix; + self.hitArea = CGPathCreateCopyByTransformingPath(hitArea, &transform); + + CGPathRelease(hitArea); + if (self.opacity == 0) { return; } @@ -56,7 +62,7 @@ [self clip:context]; CGContextSaveGState(context); - CGContextAddPath(context, self.d); + CGContextAddPath(context, path); CGContextClip(context); RNSVGBrushConverter *brushConverter = [[self getSvgView] getDefinedBrushConverter:[self.fill brushRef]]; [self.fill paint:context opacity:self.fillOpacity brushConverter:brushConverter]; @@ -78,7 +84,7 @@ } if (!fillColor) { - CGContextAddPath(context, self.d); + CGContextAddPath(context, path); CGContextReplacePathWithStrokedPath(context); CGContextClip(context); } @@ -92,11 +98,11 @@ } else { // draw fill [self clip:context]; - CGContextAddPath(context, self.d); + CGContextAddPath(context, path); CGContextDrawPath(context, mode); // draw stroke - CGContextAddPath(context, self.d); + CGContextAddPath(context, path); CGContextReplacePathWithStrokedPath(context); CGContextClip(context); RNSVGBrushConverter *brushConverter = [[self getSvgView] getDefinedBrushConverter:[self.stroke brushRef]]; @@ -106,7 +112,7 @@ } [self clip:context]; - CGContextAddPath(context, self.d); + CGContextAddPath(context, path); CGContextDrawPath(context, mode); } diff --git a/ios/RNSVGNode.h b/ios/RNSVGNode.h index 7bf52614..fe521687 100644 --- a/ios/RNSVGNode.h +++ b/ios/RNSVGNode.h @@ -24,6 +24,7 @@ @property (nonatomic, strong) NSString *clipPathRef; // use clipPath="url(#clip)" as ClipPath @property (nonatomic, assign) BOOL responsible; @property (nonatomic, assign) CGAffineTransform matrix; +@property (nonatomic, assign) BOOL active; - (void)invalidate; @@ -52,7 +53,7 @@ /** * run hitTest */ -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event withTransform:(CGAffineTransform)transfrom; - (RNSVGSvgView *)getSvgView; diff --git a/ios/RNSVGNode.m b/ios/RNSVGNode.m index bea3f2f7..32401c0e 100644 --- a/ios/RNSVGNode.m +++ b/ios/RNSVGNode.m @@ -69,12 +69,6 @@ _opacity = opacity; } -- (void)setMatrix:(CGAffineTransform)matrix -{ - self.transform = matrix; - [self invalidate]; -} - - (void)setClipPath:(CGPathRef)clipPath { if (_clipPath == clipPath) { @@ -147,7 +141,15 @@ // abstract } -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; +// hitTest delagate +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event +{ + + // abstract + return nil; +} + +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event withTransform:(CGAffineTransform)transfrom { // abstract return nil; diff --git a/ios/RNSVGRenderable.h b/ios/RNSVGRenderable.h index e433de0a..1764e76d 100644 --- a/ios/RNSVGRenderable.h +++ b/ios/RNSVGRenderable.h @@ -26,7 +26,7 @@ @property (nonatomic, assign) CGFloat strokeMiterlimit; @property (nonatomic, assign) RNSVGCGFloatArray strokeDasharray; @property (nonatomic, assign) CGFloat strokeDashoffset; -@property (nonatomic, assign) CGMutablePathRef hitArea; +@property (nonatomic, assign) CGPathRef hitArea; @property (nonatomic, copy) NSArray *propList; - (void)setBoundingBox:(CGContextRef)context; diff --git a/ios/RNSVGRenderable.m b/ios/RNSVGRenderable.m index 7be36a3e..f3157b7b 100644 --- a/ios/RNSVGRenderable.m +++ b/ios/RNSVGRenderable.m @@ -30,7 +30,7 @@ return self; } -- (void)setHitArea:(CGMutablePathRef)hitArea +- (void)setHitArea:(CGPathRef)hitArea { if (hitArea == _hitArea) { return; @@ -38,7 +38,7 @@ [self invalidate]; CGPathRelease(_hitArea); - _hitArea = hitArea; + _hitArea = CGPathRetain(hitArea); } - (void)setFill:(RNSVGBrush *)fill @@ -116,7 +116,7 @@ { // This needs to be painted on a layer before being composited. CGContextSaveGState(context); - CGContextConcatCTM(context, self.transform); + CGContextConcatCTM(context, self.matrix); CGContextSetAlpha(context, self.opacity); [self beginTransparencyLayer:context]; @@ -130,8 +130,22 @@ // hitTest delagate - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { - CGPathRef clipPath = self.clipPath; - if (self.hitArea && CGPathContainsPoint(self.hitArea, nil, point, NO)) { + return [self hitTest:point withEvent:event withTransform:CGAffineTransformMakeRotation(0)]; +} + +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event withTransform:(CGAffineTransform)transfrom +{ + if (self.active) { + if (!event) { + self.active = NO; + } + return self; + } + + CGPathRef hitArea = CGPathCreateCopyByTransformingPath(self.hitArea, &transfrom); + CGPathRef clipPath = self.clipPath; + BOOL contains = CGPathContainsPoint(hitArea, nil, point, NO); + if (contains) { if (!clipPath) { return self; } else { @@ -142,7 +156,6 @@ } } - - (void)setBoundingBox:(CGContextRef)context { _boundingBox = CGContextGetClipBoundingBox(context); diff --git a/ios/RNSVGViewBox.m b/ios/RNSVGViewBox.m index f26e53c8..298e1986 100644 --- a/ios/RNSVGViewBox.m +++ b/ios/RNSVGViewBox.m @@ -95,9 +95,9 @@ translateY -= eHeight / scaleY - vbHeight; } } - - self.transform = CGAffineTransformScale(self.transform, scaleX, scaleY); - self.transform = CGAffineTransformTranslate(self.transform, -translateX * (_fromSymbol ? scaleX : 1), -translateY * (_fromSymbol ? scaleY : 1)); + + self.matrix = CGAffineTransformMakeScale(scaleX, scaleY); + self.matrix = CGAffineTransformTranslate(self.matrix, -translateX * (_fromSymbol ? scaleX : 1), -translateY * (_fromSymbol ? scaleY : 1)); [super renderTo:context]; } diff --git a/ios/Shapes/RNSVGCircle.m b/ios/Shapes/RNSVGCircle.m index 29774083..5608c9ef 100644 --- a/ios/Shapes/RNSVGCircle.m +++ b/ios/Shapes/RNSVGCircle.m @@ -38,12 +38,6 @@ _r = r; } -- (void)renderLayerTo:(CGContextRef)context -{ - self.d = [self getPath: context]; - [super renderLayerTo:context]; -} - - (CGPathRef)getPath:(CGContextRef)context { [self setBoundingBox:context]; diff --git a/ios/Shapes/RNSVGEllipse.m b/ios/Shapes/RNSVGEllipse.m index 048ecfec..c388e663 100644 --- a/ios/Shapes/RNSVGEllipse.m +++ b/ios/Shapes/RNSVGEllipse.m @@ -47,12 +47,6 @@ _ry = ry; } -- (void)renderLayerTo:(CGContextRef)context -{ - self.d = [self getPath: context]; - [super renderLayerTo:context]; -} - - (CGPathRef)getPath:(CGContextRef)context { [self setBoundingBox:context]; diff --git a/ios/Shapes/RNSVGLine.m b/ios/Shapes/RNSVGLine.m index f9e978a5..2c8b16e7 100644 --- a/ios/Shapes/RNSVGLine.m +++ b/ios/Shapes/RNSVGLine.m @@ -47,12 +47,6 @@ _y2 = y2; } -- (void)renderLayerTo:(CGContextRef)context -{ - self.d = [self getPath: context]; - [super renderLayerTo:context]; -} - - (CGPathRef)getPath:(CGContextRef)context { [self setBoundingBox:context]; diff --git a/ios/Shapes/RNSVGRect.m b/ios/Shapes/RNSVGRect.m index ca25c245..bd91bd3e 100644 --- a/ios/Shapes/RNSVGRect.m +++ b/ios/Shapes/RNSVGRect.m @@ -65,12 +65,6 @@ _ry = ry; } -- (void)renderLayerTo:(CGContextRef)context -{ - self.d = [self getPath: context]; - [super renderLayerTo:context]; -} - - (CGPathRef)getPath:(CGContextRef)context { [self setBoundingBox:context]; diff --git a/ios/Text/RNSVGText.m b/ios/Text/RNSVGText.m index d4c294b3..1ee2ebc7 100644 --- a/ios/Text/RNSVGText.m +++ b/ios/Text/RNSVGText.m @@ -53,12 +53,6 @@ static void RNSVGFreeTextFrame(RNSVGTextFrame frame) RNSVGFreeTextFrame(_textFrame); } -- (void)renderLayerTo:(CGContextRef)context -{ - self.d = [self getPath: context]; - [super renderLayerTo:context]; -} - - (CGPathRef)getPath:(CGContextRef)context { CGMutablePathRef path = CGPathCreateMutable(); @@ -124,6 +118,7 @@ static void RNSVGFreeTextFrame(RNSVGTextFrame frame) transform = CGAffineTransformTranslate(upsideDown, point.x, point.y); } + CGPathAddPath(path, &transform, letter); } diff --git a/ios/Utils/RCTConvert+RNSVG.m b/ios/Utils/RCTConvert+RNSVG.m index bac7d127..542101f4 100644 --- a/ios/Utils/RCTConvert+RNSVG.m +++ b/ios/Utils/RCTConvert+RNSVG.m @@ -26,7 +26,7 @@ #define NEXT_VALUE [self double:arr[i++]] CGMutablePathRef path = CGPathCreateMutable(); - CGPathMoveToPoint(path, NULL, 0, 0); + CGPathMoveToPoint(path, nil, 0, 0); @try { NSUInteger i = 0; @@ -34,28 +34,28 @@ NSUInteger type = [arr[i++] unsignedIntegerValue]; switch (type) { case 0: - CGPathMoveToPoint(path, NULL, NEXT_VALUE, NEXT_VALUE); + CGPathMoveToPoint(path, nil, NEXT_VALUE, NEXT_VALUE); break; case 1: CGPathCloseSubpath(path); break; case 2: - CGPathAddLineToPoint(path, NULL, NEXT_VALUE, NEXT_VALUE); + CGPathAddLineToPoint(path, nil, NEXT_VALUE, NEXT_VALUE); break; case 3: - CGPathAddCurveToPoint(path, NULL, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE); + CGPathAddCurveToPoint(path, nil, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE, NEXT_VALUE); break; default: RCTLogError(@"Invalid CGPath type %zd at element %zd of %@", type, i, arr); CGPathRelease(path); - return NULL; + return nil; } } } @catch (NSException *exception) { RCTLogError(@"Invalid CGPath format: %@", arr); CGPathRelease(path); - return NULL; + return nil; } return (CGPathRef)CFAutorelease(path); @@ -123,7 +123,7 @@ RCT_ENUM_CONVERTER(RNSVGVBMOS, (@{ CFRelease(attrString); frame.lines[i] = line; - frame.widths[i] = CTLineGetTypographicBounds(line, NULL, NULL, NULL); + frame.widths[i] = CTLineGetTypographicBounds(line, nil, nil, nil); }]; return frame; @@ -136,7 +136,7 @@ RCT_ENUM_CONVERTER(RNSVGVBMOS, (@{ RNSVGCGFloatArray array; array.count = count; - array.array = NULL; + array.array = nil; if (count) { // Ideally, these arrays should already use the same memory layout. @@ -213,13 +213,13 @@ RCT_ENUM_CONVERTER(RNSVGVBMOS, (@{ break; default: RCTLogError(@"Invalid RNSVGBezier type %zd at element %zd of %@", type, i, arr); - return NULL; + return nil; } } } @catch (NSException *exception) { RCTLogError(@"Invalid RNSVGBezier format: %@", arr); - return NULL; + return nil; } return beziers; @@ -256,7 +256,7 @@ RCT_ENUM_CONVERTER(RNSVGVBMOS, (@{ NSArray *arr = [self NSArray:json]; if (arr.count < offset + 4) { RCTLogError(@"Too few elements in array (expected at least %zd): %@", 4 + offset, arr); - return NULL; + return nil; } return [self CGColor:[arr subarrayWithRange:(NSRange){offset, 4}]]; } @@ -266,7 +266,7 @@ RCT_ENUM_CONVERTER(RNSVGVBMOS, (@{ NSArray *arr = [self NSArray:json]; if (arr.count < offset) { RCTLogError(@"Too few elements in array (expected at least %zd): %@", offset, arr); - return NULL; + return nil; } arr = [arr subarrayWithRange:(NSRange){offset, arr.count - offset}]; RNSVGCGFloatArray colorsAndOffsets = [self RNSVGCGFloatArray:arr];