From de01bb8638d8bdaeea59a2fe17447e16e788be86 Mon Sep 17 00:00:00 2001 From: Maksym Komarychev Date: Thu, 5 Apr 2018 16:05:37 +0300 Subject: [PATCH 1/4] [ios] Fix touch handling in groups Check all children before current node itself. Add shortcut check to return active node if `event` is null. Otherwise it may return wrong node which have higher z-index value. --- ios/Elements/RNSVGGroup.m | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/ios/Elements/RNSVGGroup.m b/ios/Elements/RNSVGGroup.m index 14138de2..85bd1dd6 100644 --- a/ios/Elements/RNSVGGroup.m +++ b/ios/Elements/RNSVGGroup.m @@ -61,6 +61,7 @@ return YES; }]; + [self setHitArea:[self getPath:context]]; [self popGlyphContext]; } @@ -113,16 +114,19 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix); - - UIView *hitSelf = [super hitTest:transformed withEvent:event]; - if (hitSelf) { - return hitSelf; - } - + CGPathRef clip = [self getClipPath]; if (clip && !CGPathContainsPoint(clip, nil, transformed, self.clipRule == kRNSVGCGFCRuleEvenodd)) { return nil; } + + if (!event) { + NSPredicate *const anyActive = [NSPredicate predicateWithFormat:@"active == TRUE"]; + NSArray *const filtered = [self.subviews filteredArrayUsingPredicate:anyActive]; + if ([filtered count] != 0) { + return filtered.firstObject; + } + } for (RNSVGNode *node in [self.subviews reverseObjectEnumerator]) { if (![node isKindOfClass:[RNSVGNode class]]) { @@ -142,7 +146,12 @@ return (node.responsible || (node != hitChild)) ? hitChild : self; } } - + + UIView *hitSelf = [super hitTest:transformed withEvent:event]; + if (hitSelf) { + return hitSelf; + } + return nil; } From 2d698e92d5187262c4481024bb318f4fa0e4145a Mon Sep 17 00:00:00 2001 From: Maksym Komarychev Date: Thu, 5 Apr 2018 18:34:05 +0300 Subject: [PATCH 2/4] [ios] Handle touches within `use` --- ios/Elements/RNSVGUse.m | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ios/Elements/RNSVGUse.m b/ios/Elements/RNSVGUse.m index ab2f4af7..cd9dcf87 100644 --- a/ios/Elements/RNSVGUse.m +++ b/ios/Elements/RNSVGUse.m @@ -51,5 +51,21 @@ } } +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { + const CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix); + RNSVGNode const* template = [self.svgView getDefinedTemplate:self.href]; + if (event) { + self.active = NO; + } else if (self.active) { + return self; + } + UIView const* hitChild = [template hitTest:transformed withEvent:event]; + if (hitChild) { + self.active = YES; + return self; + } + return nil; +} + @end From 374d16637245ca3f378d52518a3fb8d187431892 Mon Sep 17 00:00:00 2001 From: Maksym Komarychev Date: Fri, 13 Apr 2018 23:53:02 +0300 Subject: [PATCH 3/4] [ios] save hit area even if not responsible --- ios/RNSVGRenderable.m | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/ios/RNSVGRenderable.m b/ios/RNSVGRenderable.m index 74414460..b6821200 100644 --- a/ios/RNSVGRenderable.m +++ b/ios/RNSVGRenderable.m @@ -264,21 +264,19 @@ { CGPathRelease(_hitArea); _hitArea = nil; - if (self.responsible) { - // Add path to hitArea - CGMutablePathRef hitArea = CGPathCreateMutableCopy(path); - - if (self.stroke && self.strokeWidth) { - // Add stroke to hitArea - CGFloat width = [self relativeOnOther:self.strokeWidth]; - CGPathRef strokePath = CGPathCreateCopyByStrokingPath(hitArea, nil, width, self.strokeLinecap, self.strokeLinejoin, self.strokeMiterlimit); - CGPathAddPath(hitArea, nil, strokePath); - CGPathRelease(strokePath); - } - - _hitArea = CGPathRetain(CFAutorelease(CGPathCreateCopy(hitArea))); - CGPathRelease(hitArea); + // Add path to hitArea + CGMutablePathRef hitArea = CGPathCreateMutableCopy(path); + + if (self.stroke && self.strokeWidth) { + // Add stroke to hitArea + CGFloat width = [self relativeOnOther:self.strokeWidth]; + CGPathRef strokePath = CGPathCreateCopyByStrokingPath(hitArea, nil, width, self.strokeLinecap, self.strokeLinejoin, self.strokeMiterlimit); + CGPathAddPath(hitArea, nil, strokePath); + CGPathRelease(strokePath); } + + _hitArea = CGPathRetain(CFAutorelease(CGPathCreateCopy(hitArea))); + CGPathRelease(hitArea); } From 3440d722775d4eb671ec39d3c95a0388b25b192f Mon Sep 17 00:00:00 2001 From: Maksym Komarychev Date: Fri, 6 Apr 2018 10:54:59 +0300 Subject: [PATCH 4/4] [android] hitTest for `Use` --- .../java/com/horcrux/svg/UseShadowNode.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/android/src/main/java/com/horcrux/svg/UseShadowNode.java b/android/src/main/java/com/horcrux/svg/UseShadowNode.java index 909529a1..1c5592ec 100644 --- a/android/src/main/java/com/horcrux/svg/UseShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/UseShadowNode.java @@ -73,6 +73,24 @@ class UseShadowNode extends RenderableShadowNode { } } + @Override + public int hitTest(float[] src) { + if (!mInvertible) { + return -1; + } + + float[] dst = new float[2]; + mInvMatrix.mapPoints(dst, src); + + VirtualNode template = getSvgShadowNode().getDefinedTemplate(mHref); + int hitChild = template.hitTest(dst); + if (hitChild != -1) { + return (template.isResponsible() || hitChild != template.getReactTag()) ? hitChild : getReactTag(); + } + + return -1; + } + @Override protected Path getPath(Canvas canvas, Paint paint) { // todo: