From ad99f97c84126ad1a66b5718d98f2adfaf3beb16 Mon Sep 17 00:00:00 2001 From: Mikael Sand Date: Mon, 24 Sep 2018 01:41:30 +0300 Subject: [PATCH] Fix onPress/In/Out and responder handling --- .../main/java/com/horcrux/svg/SvgView.java | 118 +----------------- elements/Svg.js | 5 +- ios/Elements/RNSVGGroup.m | 1 + ios/Elements/RNSVGUse.m | 7 +- ios/RNSVGRenderable.m | 1 + 5 files changed, 16 insertions(+), 116 deletions(-) diff --git a/android/src/main/java/com/horcrux/svg/SvgView.java b/android/src/main/java/com/horcrux/svg/SvgView.java index a9e57cab..ecf06d4e 100644 --- a/android/src/main/java/com/horcrux/svg/SvgView.java +++ b/android/src/main/java/com/horcrux/svg/SvgView.java @@ -13,19 +13,12 @@ import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Point; -import android.util.Log; -import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import com.facebook.react.ReactRootView; import com.facebook.react.bridge.ReactContext; +import com.facebook.react.uimanager.ReactCompoundView; import com.facebook.react.uimanager.ReactShadowNodeImpl; -import com.facebook.react.uimanager.UIManagerModule; -import com.facebook.react.uimanager.events.EventDispatcher; -import com.facebook.react.uimanager.events.TouchEvent; -import com.facebook.react.uimanager.events.TouchEventCoalescingKeyHelper; -import com.facebook.react.uimanager.events.TouchEventType; import com.facebook.react.views.view.ReactViewGroup; import javax.annotation.Nullable; @@ -34,7 +27,8 @@ import javax.annotation.Nullable; * Custom {@link View} implementation that draws an RNSVGSvg React view and its children. */ @SuppressLint("ViewConstructor") -public class SvgView extends ViewGroup { +public class SvgView extends ViewGroup implements ReactCompoundView { + @SuppressWarnings("unused") public enum Events { @SuppressWarnings("unused") @@ -54,16 +48,9 @@ public class SvgView extends ViewGroup { } private @Nullable Bitmap mBitmap; - private final EventDispatcher mEventDispatcher; - private long mGestureStartTime = TouchEvent.UNSET; - private int mTargetTag; - - private final TouchEventCoalescingKeyHelper mTouchEventCoalescingKeyHelper = - new TouchEventCoalescingKeyHelper(); public SvgView(ReactContext reactContext) { super(reactContext); - mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher(); } public void addView(View child, int index, LayoutParams params) { @@ -105,17 +92,12 @@ public class SvgView extends ViewGroup { } @Override - public boolean dispatchTouchEvent(MotionEvent ev) { + public int reactTagForTouch(float touchX, float touchY) { SvgViewShadowNode node = getShadowNode(); if (node != null) { - mTargetTag = node.hitTest(new Point((int) ev.getX(), (int) ev.getY())); - if (mTargetTag != -1) { - handleTouchEvent(ev); - return true; - } + return node.hitTest(new Point((int) touchX, (int) touchY)); } - - return super.dispatchTouchEvent(ev); + return getId(); } @Override @@ -144,92 +126,4 @@ public class SvgView extends ViewGroup { } } } - - private int getAbsoluteLeft(View view) { - int left = view.getLeft() - view.getScrollX(); - - if (view.getParent() == view.getRootView() || view.getParent() instanceof ReactRootView) { - return left; - } - - View parent = (View) view.getParent(); - return left + getAbsoluteLeft(parent); - } - - private int getAbsoluteTop(View view) { - int top = view.getTop() - view.getScrollY(); - - if (view.getParent() == view.getRootView() || view.getParent() instanceof ReactRootView) { - return top; - } - - View parent = (View) view.getParent(); - return top + getAbsoluteTop(parent); - } - - private void dispatch(MotionEvent ev, TouchEventType type) { - ev.offsetLocation(getAbsoluteLeft(this), getAbsoluteTop(this)); - mEventDispatcher.dispatchEvent( - TouchEvent.obtain( - mTargetTag, - type, - ev, - mGestureStartTime, - ev.getX(), - ev.getY(), - mTouchEventCoalescingKeyHelper)); - } - - private void handleTouchEvent(MotionEvent ev) { - int action = ev.getAction() & MotionEvent.ACTION_MASK; - if (action == MotionEvent.ACTION_DOWN) { - mGestureStartTime = ev.getEventTime(); - dispatch(ev, TouchEventType.START); - } else if (mTargetTag == -1) { - // All the subsequent action types are expected to be called after ACTION_DOWN thus target - // is supposed to be set for them. - Log.e( - "error", - "Unexpected state: received touch event but didn't get starting ACTION_DOWN for this " + - "gesture before"); - } else if (action == MotionEvent.ACTION_UP) { - // End of the gesture. We reset target tag to -1 and expect no further event associated with - // this gesture. - dispatch(ev, TouchEventType.END); - mTargetTag = -1; - mGestureStartTime = TouchEvent.UNSET; - } else if (action == MotionEvent.ACTION_MOVE) { - // Update pointer position for current gesture - dispatch(ev, TouchEventType.MOVE); - } else if (action == MotionEvent.ACTION_POINTER_DOWN) { - // New pointer goes down, this can only happen after ACTION_DOWN is sent for the first pointer - dispatch(ev, TouchEventType.START); - } else if (action == MotionEvent.ACTION_POINTER_UP) { - // Exactly onw of the pointers goes up - dispatch(ev, TouchEventType.END); - } else if (action == MotionEvent.ACTION_CANCEL) { - dispatchCancelEvent(ev); - mTargetTag = -1; - mGestureStartTime = TouchEvent.UNSET; - } else { - Log.w( - "IGNORE", - "Warning : touch event was ignored. Action=" + action + " Target=" + mTargetTag); - } - } - - private void dispatchCancelEvent(MotionEvent ev) { - // This means the gesture has already ended, via some other CANCEL or UP event. This is not - // expected to happen very often as it would mean some child View has decided to intercept the - // touch stream and start a native gesture only upon receiving the UP/CANCEL event. - if (mTargetTag == -1) { - Log.w( - "error", - "Can't cancel already finished gesture. Is a child View trying to start a gesture from " + - "an UP/CANCEL event?"); - return; - } - - dispatch(ev, TouchEventType.CANCEL); - } } diff --git a/elements/Svg.js b/elements/Svg.js index 1563b200..df612362 100644 --- a/elements/Svg.js +++ b/elements/Svg.js @@ -8,9 +8,11 @@ import { findNodeHandle, NativeModules } from "react-native"; +import extractResponder from "../lib/extract/extractResponder"; import extractViewBox from "../lib/extract/extractViewBox"; import { ViewBoxAttributes } from "../lib/attributes"; import { numberProp } from "../lib/props"; +import Shape from "./Shape"; /** @namespace NativeModules.RNSVGSvgViewManager */ const RNSVGSvgViewManager = NativeModules.RNSVGSvgViewManager; @@ -24,7 +26,7 @@ const styles = StyleSheet.create({ } }); -class Svg extends Component { +class Svg extends Shape { static displayName = "Svg"; static propTypes = { ...ViewPropTypes, @@ -93,6 +95,7 @@ class Svg extends Component { {...props} bbWidth={w} bbHeight={h} + {...extractResponder(props, this)} {...extractViewBox({ viewBox, preserveAspectRatio })} ref={ele => { this.root = ele; diff --git a/ios/Elements/RNSVGGroup.m b/ios/Elements/RNSVGGroup.m index 1871994c..d152e0e2 100644 --- a/ios/Elements/RNSVGGroup.m +++ b/ios/Elements/RNSVGGroup.m @@ -73,6 +73,7 @@ }]; [self setHitArea:[self getPath:context]]; self.clientRect = groupRect; + self.bounds = groupRect; [self popGlyphContext]; } diff --git a/ios/Elements/RNSVGUse.m b/ios/Elements/RNSVGUse.m index f278dde2..282d3787 100644 --- a/ios/Elements/RNSVGUse.m +++ b/ios/Elements/RNSVGUse.m @@ -16,7 +16,7 @@ if ([href isEqualToString:_href]) { return; } - + [self invalidate]; _href = href; } @@ -26,7 +26,7 @@ if ([usewidth isEqualToString:_usewidth]) { return; } - + [self invalidate]; _usewidth = usewidth; } @@ -36,7 +36,7 @@ if ([useheight isEqualToString:_useheight]) { return; } - + [self invalidate]; _useheight = useheight; } @@ -69,6 +69,7 @@ RCTLogWarn(@"`Use` element expected a pre-defined svg template as `href` prop, template named: %@ is not defined.", self.href); } self.clientRect = template.clientRect; + self.bounds = template.clientRect; } - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { diff --git a/ios/RNSVGRenderable.m b/ios/RNSVGRenderable.m index f7471d3a..f60a67ed 100644 --- a/ios/RNSVGRenderable.m +++ b/ios/RNSVGRenderable.m @@ -289,6 +289,7 @@ UInt32 saturate(double value) { const CGRect pathBounding = CGPathGetBoundingBox(self.path); const CGAffineTransform svgToClientTransform = CGAffineTransformConcat(CGContextGetCTM(context), self.svgView.invInitialCTM); self.clientRect = CGRectApplyAffineTransform(pathBounding, svgToClientTransform); + self.bounds = self.clientRect; CGPathDrawingMode mode = kCGPathStroke; BOOL fillColor = NO;