mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-06 16:32:24 +00:00
add touch responder system on android
This commit is contained in:
@@ -62,19 +62,14 @@ public class RNSVGCircleShadowNode extends RNSVGPathShadowNode {
|
||||
@Override
|
||||
protected Path getPath(Canvas canvas, Paint paint) {
|
||||
Path path = new Path();
|
||||
|
||||
Rect box = canvas.getClipBounds();
|
||||
float height = box.height();
|
||||
float width = box.width();
|
||||
|
||||
float cx = PropHelper.fromPercentageToFloat(mCx, width, 0, mScale);
|
||||
float cy = PropHelper.fromPercentageToFloat(mCy, height, 0, mScale);
|
||||
float cx = PropHelper.fromPercentageToFloat(mCx, mWidth, 0, mScale);
|
||||
float cy = PropHelper.fromPercentageToFloat(mCy, mHeight, 0, mScale);
|
||||
|
||||
float r;
|
||||
if (PropHelper.isPercentage(mR)) {
|
||||
r = PropHelper.fromPercentageToFloat(mR, 1, 0, 1);
|
||||
float powX = (float)Math.pow((width * r), 2);
|
||||
float powY = (float)Math.pow((height * r), 2);
|
||||
float powX = (float)Math.pow((mWidth * r), 2);
|
||||
float powY = (float)Math.pow((mHeight * r), 2);
|
||||
r = (float)Math.sqrt(powX + powY) / (float)Math.sqrt(2);
|
||||
} else {
|
||||
r = Float.parseFloat(mR) * mScale;
|
||||
|
||||
@@ -65,15 +65,11 @@ public class RNSVGEllipseShadowNode extends RNSVGPathShadowNode {
|
||||
protected Path getPath(Canvas canvas, Paint paint) {
|
||||
Path path = new Path();
|
||||
|
||||
Rect box = canvas.getClipBounds();
|
||||
float height = box.height();
|
||||
float width = box.width();
|
||||
|
||||
// draw ellipse
|
||||
float cx = PropHelper.fromPercentageToFloat(mCx, width, 0, mScale);
|
||||
float cy = PropHelper.fromPercentageToFloat(mCy, height, 0, mScale);
|
||||
float rx = PropHelper.fromPercentageToFloat(mRx, width, 0, mScale);
|
||||
float ry = PropHelper.fromPercentageToFloat(mRy, height, 0, mScale);
|
||||
float cx = PropHelper.fromPercentageToFloat(mCx, mWidth, 0, mScale);
|
||||
float cy = PropHelper.fromPercentageToFloat(mCy, mHeight, 0, mScale);
|
||||
float rx = PropHelper.fromPercentageToFloat(mRx, mWidth, 0, mScale);
|
||||
float ry = PropHelper.fromPercentageToFloat(mRy, mHeight, 0, mScale);
|
||||
RectF oval = new RectF(cx - rx, cy - ry, cx + rx, cy + ry);
|
||||
path.addOval(oval, Path.Direction.CW);
|
||||
|
||||
|
||||
@@ -12,7 +12,10 @@ package com.horcrux.svg;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Point;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
|
||||
@@ -29,12 +32,6 @@ public class RNSVGGroupShadowNode extends RNSVGVirtualNode {
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isVirtual() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas, Paint paint, float opacity) {
|
||||
opacity *= mOpacity;
|
||||
if (opacity > MIN_OPACITY_FOR_DRAW) {
|
||||
@@ -43,6 +40,7 @@ public class RNSVGGroupShadowNode extends RNSVGVirtualNode {
|
||||
if (mAsClipPath == null) {
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
RNSVGVirtualNode child = (RNSVGVirtualNode) getChildAt(i);
|
||||
child.setDimensions(mWidth, mHeight);
|
||||
child.draw(canvas, paint, opacity);
|
||||
child.markUpdateSeen();
|
||||
}
|
||||
@@ -62,4 +60,23 @@ public class RNSVGGroupShadowNode extends RNSVGVirtualNode {
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hitTest(Point point, View view) {
|
||||
// TODO: run hit test only if necessary
|
||||
// TODO: ClipPath never run hitTest
|
||||
if (mClipPathId == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int viewTag = -1;
|
||||
for (int i = getChildCount() - 1; i >= 0; i--) {
|
||||
viewTag = ((RNSVGVirtualNode) getChildAt(i)).hitTest(point, ((ViewGroup) view).getChildAt(i));
|
||||
if (viewTag != -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return viewTag;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
|
||||
bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e("URI", "" + e);
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
@@ -131,6 +132,7 @@ public class RNSVGImageShadowNode extends RNSVGPathShadowNode {
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint, float opacity) {
|
||||
canvas.saveLayer(0f, 0f, 0f, 0f, paint, Canvas.ALL_SAVE_FLAG);
|
||||
Log.e("Count", "" + canvas.getSaveCount());
|
||||
loadBitmap(getResourceDrawableId(getThemedContext(), null), canvas, paint);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,14 +69,10 @@ public class RNSVGLineShadowNode extends RNSVGPathShadowNode {
|
||||
protected Path getPath(Canvas canvas, Paint paint) {
|
||||
Path path = new Path();
|
||||
|
||||
Rect box = canvas.getClipBounds();
|
||||
float height = box.height();
|
||||
float width = box.width();
|
||||
|
||||
float x1 = PropHelper.fromPercentageToFloat(mX1, width, 0, mScale);
|
||||
float y1 = PropHelper.fromPercentageToFloat(mY1, height, 0, mScale);
|
||||
float x2 = PropHelper.fromPercentageToFloat(mX2, width, 0, mScale);
|
||||
float y2 = PropHelper.fromPercentageToFloat(mY2, height, 0, mScale);
|
||||
float x1 = PropHelper.fromPercentageToFloat(mX1, mWidth, 0, mScale);
|
||||
float y1 = PropHelper.fromPercentageToFloat(mY1, mHeight, 0, mScale);
|
||||
float x2 = PropHelper.fromPercentageToFloat(mX2, mWidth, 0, mScale);
|
||||
float y2 = PropHelper.fromPercentageToFloat(mY2, mHeight, 0, mScale);
|
||||
|
||||
path.moveTo(x1, y1);
|
||||
path.lineTo(x2, y2);
|
||||
|
||||
@@ -11,6 +11,7 @@ package com.horcrux.svg;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.DashPathEffect;
|
||||
import android.graphics.Paint;
|
||||
@@ -26,6 +27,8 @@ import android.graphics.Region;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.Matrix;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
@@ -53,14 +56,14 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
|
||||
private @Nullable float[] mStrokeDasharray;
|
||||
private float mStrokeWidth = 1;
|
||||
private float mStrokeDashoffset = 0;
|
||||
private int mStrokeLinecap = CAP_ROUND;
|
||||
private int mStrokeLinejoin = JOIN_ROUND;
|
||||
private int mFillRule = FILL_RULE_NONZERO;
|
||||
private Paint.Cap mStrokeLinecap = Paint.Cap.ROUND;
|
||||
private Paint.Join mStrokeLinejoin = Paint.Join.ROUND;
|
||||
private Path.FillType mFillRule = Path.FillType.WINDING;
|
||||
private boolean mFillRuleSet;
|
||||
protected Path mPath;
|
||||
private boolean mPathSet;
|
||||
private float[] mD;
|
||||
private Point mPaint;
|
||||
|
||||
|
||||
@ReactProp(name = "d")
|
||||
public void setPath(@Nullable ReadableArray shapePath) {
|
||||
@@ -79,7 +82,17 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
|
||||
|
||||
@ReactProp(name = "fillRule", defaultInt = FILL_RULE_NONZERO)
|
||||
public void setFillRule(int fillRule) {
|
||||
mFillRule = fillRule;
|
||||
switch (fillRule) {
|
||||
case FILL_RULE_EVENODD:
|
||||
mFillRule = Path.FillType.EVEN_ODD;
|
||||
break;
|
||||
case FILL_RULE_NONZERO:
|
||||
break;
|
||||
default:
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
"fillRule " + mFillRule + " unrecognized");
|
||||
}
|
||||
|
||||
mFillRuleSet = true;
|
||||
setupPath();
|
||||
markUpdated();
|
||||
@@ -117,13 +130,39 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
|
||||
|
||||
@ReactProp(name = "strokeLinecap", defaultInt = CAP_ROUND)
|
||||
public void setStrokeLinecap(int strokeLinecap) {
|
||||
mStrokeLinecap = strokeLinecap;
|
||||
switch (strokeLinecap) {
|
||||
case CAP_BUTT:
|
||||
mStrokeLinecap = Paint.Cap.BUTT;
|
||||
break;
|
||||
case CAP_SQUARE:
|
||||
mStrokeLinecap = Paint.Cap.SQUARE;
|
||||
break;
|
||||
case CAP_ROUND:
|
||||
mStrokeLinecap = Paint.Cap.ROUND;
|
||||
break;
|
||||
default:
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
"strokeLinecap " + mStrokeLinecap + " unrecognized");
|
||||
}
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "strokeLinejoin", defaultInt = JOIN_ROUND)
|
||||
public void setStrokeLinejoin(int strokeLinejoin) {
|
||||
mStrokeLinejoin = strokeLinejoin;
|
||||
switch (strokeLinejoin) {
|
||||
case JOIN_MITER:
|
||||
mStrokeLinejoin = Paint.Join.MITER;
|
||||
break;
|
||||
case JOIN_BEVEL:
|
||||
mStrokeLinejoin = Paint.Join.BEVEL;
|
||||
break;
|
||||
case JOIN_ROUND:
|
||||
mStrokeLinejoin = Paint.Join.ROUND;
|
||||
break;
|
||||
default:
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
"strokeLinejoin " + mStrokeLinejoin + " unrecognized");
|
||||
}
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@@ -178,7 +217,7 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
|
||||
|
||||
|
||||
/**
|
||||
* Sets up {@link #mPaint} according to the props set on a shadow view. Returns {@code true}
|
||||
* Sets up paint according to the props set on a shadow view. Returns {@code true}
|
||||
* if the fill should be drawn, {@code false} if not.
|
||||
*/
|
||||
protected boolean setupFillPaint(Paint paint, float opacity, @Nullable RectF box) {
|
||||
@@ -193,7 +232,7 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up {@link #mPaint} according to the props set on a shadow view. Returns {@code true}
|
||||
* Sets up paint according to the props set on a shadow view. Returns {@code true}
|
||||
* if the stroke should be drawn, {@code false} if not.
|
||||
*/
|
||||
protected boolean setupStrokePaint(Paint paint, float opacity, @Nullable RectF box) {
|
||||
@@ -203,35 +242,8 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
|
||||
paint.reset();
|
||||
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
switch (mStrokeLinecap) {
|
||||
case CAP_BUTT:
|
||||
paint.setStrokeCap(Paint.Cap.BUTT);
|
||||
break;
|
||||
case CAP_SQUARE:
|
||||
paint.setStrokeCap(Paint.Cap.SQUARE);
|
||||
break;
|
||||
case CAP_ROUND:
|
||||
paint.setStrokeCap(Paint.Cap.ROUND);
|
||||
break;
|
||||
default:
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
"strokeLinecap " + mStrokeLinecap + " unrecognized");
|
||||
}
|
||||
switch (mStrokeLinejoin) {
|
||||
case JOIN_MITER:
|
||||
paint.setStrokeJoin(Paint.Join.MITER);
|
||||
break;
|
||||
case JOIN_BEVEL:
|
||||
paint.setStrokeJoin(Paint.Join.BEVEL);
|
||||
break;
|
||||
case JOIN_ROUND:
|
||||
paint.setStrokeJoin(Paint.Join.ROUND);
|
||||
break;
|
||||
default:
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
"strokeLinejoin " + mStrokeLinejoin + " unrecognized");
|
||||
}
|
||||
|
||||
paint.setStrokeCap(mStrokeLinecap);
|
||||
paint.setStrokeJoin(mStrokeLinejoin);
|
||||
paint.setStrokeWidth(mStrokeWidth * mScale);
|
||||
setupPaint(paint, opacity, mStrokeColor, box);
|
||||
|
||||
@@ -312,21 +324,67 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode {
|
||||
// TODO: Support pattern.
|
||||
FLog.w(ReactConstants.TAG, "RNSVG: Color type " + colorType + " not supported!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected Path getPath(@Nullable Canvas canvas, @Nullable Paint paint) {
|
||||
Path path = new Path();
|
||||
switch (mFillRule) {
|
||||
case FILL_RULE_EVENODD:
|
||||
path.setFillType(Path.FillType.EVEN_ODD);
|
||||
break;
|
||||
case FILL_RULE_NONZERO:
|
||||
break;
|
||||
default:
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
"fillRule " + mFillRule + " unrecognized");
|
||||
}
|
||||
path.setFillType(mFillRule);
|
||||
super.createPath(mD, path);
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hitTest(Point point, View view) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(
|
||||
(int) mWidth,
|
||||
(int) mHeight,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
canvas.concat(mMatrix);
|
||||
|
||||
Paint paint = new Paint();
|
||||
clip(canvas, paint);
|
||||
setHitTestFill(paint);
|
||||
canvas.drawPath(mPath, paint);
|
||||
|
||||
if (setHitTestStroke(paint)) {
|
||||
canvas.drawPath(mPath, paint);
|
||||
}
|
||||
|
||||
canvas.setBitmap(bitmap);
|
||||
try {
|
||||
if (bitmap.getPixel(point.x, point.y) != 0) {
|
||||
return view.getId();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return -1;
|
||||
} finally {
|
||||
bitmap.recycle();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected void setHitTestFill(Paint paint) {
|
||||
paint.reset();
|
||||
paint.setARGB(255, 0, 0, 0);
|
||||
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
}
|
||||
|
||||
protected boolean setHitTestStroke(Paint paint) {
|
||||
if (mStrokeWidth == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
paint.reset();
|
||||
paint.setARGB(255, 0, 0, 0);
|
||||
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(mStrokeWidth * mScale);
|
||||
paint.setStrokeCap(mStrokeLinecap);
|
||||
paint.setStrokeJoin(mStrokeLinejoin);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,9 +31,9 @@ public class RNSVGRectShadowNode extends RNSVGPathShadowNode {
|
||||
|
||||
private String mY;
|
||||
|
||||
private String mWidth;
|
||||
private String mW;
|
||||
|
||||
private String mHeight;
|
||||
private String mH;
|
||||
|
||||
private String mRx;
|
||||
|
||||
@@ -54,14 +54,14 @@ public class RNSVGRectShadowNode extends RNSVGPathShadowNode {
|
||||
|
||||
@ReactProp(name = "width")
|
||||
public void setWidth(String width) {
|
||||
mWidth = width;
|
||||
mW = width;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
|
||||
@ReactProp(name = "height")
|
||||
public void setHeight(String height) {
|
||||
mHeight = height;
|
||||
mH = height;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@@ -88,16 +88,12 @@ public class RNSVGRectShadowNode extends RNSVGPathShadowNode {
|
||||
protected Path getPath(Canvas canvas, Paint paint) {
|
||||
Path path = new Path();
|
||||
|
||||
Rect box = canvas.getClipBounds();
|
||||
float height = box.height();
|
||||
float width = box.width();
|
||||
|
||||
float x = PropHelper.fromPercentageToFloat(mX, width, 0, mScale);
|
||||
float y = PropHelper.fromPercentageToFloat(mY, height, 0, mScale);
|
||||
float w = PropHelper.fromPercentageToFloat(mWidth, width, 0, mScale);
|
||||
float h = PropHelper.fromPercentageToFloat(mHeight, height, 0, mScale);
|
||||
float rx = PropHelper.fromPercentageToFloat(mRx, width, 0, mScale);
|
||||
float ry = PropHelper.fromPercentageToFloat(mRy, height, 0, mScale);
|
||||
float x = PropHelper.fromPercentageToFloat(mX, mWidth, 0, mScale);
|
||||
float y = PropHelper.fromPercentageToFloat(mY, mHeight, 0, mScale);
|
||||
float w = PropHelper.fromPercentageToFloat(mW, mWidth, 0, mScale);
|
||||
float h = PropHelper.fromPercentageToFloat(mH, mHeight, 0, mScale);
|
||||
float rx = PropHelper.fromPercentageToFloat(mRx, mWidth, 0, mScale);
|
||||
float ry = PropHelper.fromPercentageToFloat(mRy, mHeight, 0, mScale);
|
||||
|
||||
if (rx != 0 || ry != 0) {
|
||||
if (rx == 0) {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Horcrux.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the MIT-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
|
||||
package com.horcrux.svg;
|
||||
|
||||
import android.content.Context;
|
||||
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.infer.annotation.Assertions;
|
||||
import com.facebook.react.common.SystemClock;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
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.TouchEventType;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
// NativeGestureUtil.notifyNativeGestureStarted
|
||||
|
||||
/**
|
||||
* Custom {@link View} implementation that draws an RNSVGSvg React view and its \children.
|
||||
*/
|
||||
public class RNSVGRenderableView extends ViewGroup {
|
||||
|
||||
public RNSVGRenderableView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -9,22 +9,32 @@
|
||||
|
||||
package com.horcrux.svg;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
//import com.facebook.react.uimanager.ReactStylesDiffMap;
|
||||
import com.facebook.react.common.SystemClock;
|
||||
import com.facebook.react.touch.JSResponderHandler;
|
||||
import com.facebook.react.touch.ReactInterceptingViewGroup;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.ViewGroupManager;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.react.uimanager.events.TouchEvent;
|
||||
|
||||
/**
|
||||
* ViewManager for all shadowed RNSVG views: Group, Path and Text. Since these never get rendered
|
||||
* into native views and don't need any logic (all the logic is in {@link RNSVGSvgView}), this
|
||||
* "stubbed" ViewManager is used for all of them.
|
||||
*/
|
||||
public class RNSVGRenderableViewManager extends ViewManager<View, ReactShadowNode> {
|
||||
public class RNSVGRenderableViewManager extends ViewGroupManager<ViewGroup> {
|
||||
|
||||
/* package */ static final String CLASS_GROUP = "RNSVGGroup";
|
||||
/* package */ static final String CLASS_SVG = "RNSVGPath";
|
||||
/* package */ static final String CLASS_PATH = "RNSVGPath";
|
||||
/* package */ static final String CLASS_TEXT = "RNSVGText";
|
||||
/* package */ static final String CLASS_IMAGE = "RNSVGImage";
|
||||
/* package */ static final String CLASS_CIRCLE = "RNSVGCircle";
|
||||
@@ -34,12 +44,14 @@ public class RNSVGRenderableViewManager extends ViewManager<View, ReactShadowNod
|
||||
|
||||
private final String mClassName;
|
||||
|
||||
protected RNSVGVirtualNode mVirtualNode;
|
||||
|
||||
public static RNSVGRenderableViewManager createRNSVGGroupViewManager() {
|
||||
return new RNSVGRenderableViewManager(CLASS_GROUP);
|
||||
}
|
||||
|
||||
public static RNSVGRenderableViewManager createRNSVGPathViewManager() {
|
||||
return new RNSVGRenderableViewManager(CLASS_SVG);
|
||||
return new RNSVGRenderableViewManager(CLASS_PATH);
|
||||
}
|
||||
|
||||
public static RNSVGRenderableViewManager createRNSVGTextViewManager() {
|
||||
@@ -76,58 +88,66 @@ public class RNSVGRenderableViewManager extends ViewManager<View, ReactShadowNod
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactShadowNode createShadowNodeInstance() {
|
||||
if (mClassName == CLASS_GROUP) {
|
||||
return new RNSVGGroupShadowNode();
|
||||
} else if (mClassName == CLASS_SVG) {
|
||||
return new RNSVGPathShadowNode();
|
||||
} else if (mClassName == CLASS_CIRCLE) {
|
||||
return new RNSVGCircleShadowNode();
|
||||
} else if (mClassName == CLASS_ELLIPSE) {
|
||||
return new RNSVGEllipseShadowNode();
|
||||
} else if (mClassName == CLASS_LINE) {
|
||||
return new RNSVGLineShadowNode();
|
||||
} else if (mClassName == CLASS_RECT) {
|
||||
return new RNSVGRectShadowNode();
|
||||
} else if (mClassName == CLASS_TEXT) {
|
||||
return new RNSVGTextShadowNode();
|
||||
} else if (mClassName == CLASS_IMAGE) {
|
||||
return new RNSVGImageShadowNode();
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected type " + mClassName);
|
||||
public RNSVGVirtualNode createShadowNodeInstance() {
|
||||
switch (mClassName) {
|
||||
case CLASS_GROUP:
|
||||
mVirtualNode = new RNSVGGroupShadowNode();
|
||||
break;
|
||||
case CLASS_PATH:
|
||||
mVirtualNode = new RNSVGPathShadowNode();
|
||||
break;
|
||||
case CLASS_CIRCLE:
|
||||
mVirtualNode = new RNSVGCircleShadowNode();
|
||||
break;
|
||||
case CLASS_ELLIPSE:
|
||||
mVirtualNode = new RNSVGEllipseShadowNode();
|
||||
break;
|
||||
case CLASS_LINE:
|
||||
mVirtualNode = new RNSVGLineShadowNode();
|
||||
break;
|
||||
case CLASS_RECT:
|
||||
mVirtualNode = new RNSVGRectShadowNode();
|
||||
break;
|
||||
case CLASS_TEXT:
|
||||
mVirtualNode = new RNSVGTextShadowNode();
|
||||
break;
|
||||
case CLASS_IMAGE:
|
||||
mVirtualNode = new RNSVGImageShadowNode();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected type " + mClassName);
|
||||
}
|
||||
|
||||
return mVirtualNode;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends RNSVGVirtualNode> getShadowNodeClass() {
|
||||
switch (mClassName) {
|
||||
case CLASS_GROUP:
|
||||
return RNSVGGroupShadowNode.class;
|
||||
case CLASS_PATH:
|
||||
return RNSVGPathShadowNode.class;
|
||||
case CLASS_CIRCLE:
|
||||
return RNSVGCircleShadowNode.class;
|
||||
case CLASS_ELLIPSE:
|
||||
return RNSVGEllipseShadowNode.class;
|
||||
case CLASS_LINE:
|
||||
return RNSVGLineShadowNode.class;
|
||||
case CLASS_RECT:
|
||||
return RNSVGRectShadowNode.class;
|
||||
case CLASS_TEXT:
|
||||
return RNSVGTextShadowNode.class;
|
||||
case CLASS_IMAGE:
|
||||
return RNSVGImageShadowNode.class;
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected type " + mClassName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ReactShadowNode> getShadowNodeClass() {
|
||||
if (mClassName == CLASS_GROUP) {
|
||||
return RNSVGGroupShadowNode.class;
|
||||
} else if (mClassName == CLASS_SVG) {
|
||||
return RNSVGPathShadowNode.class;
|
||||
} else if (mClassName == CLASS_CIRCLE) {
|
||||
return RNSVGCircleShadowNode.class;
|
||||
} else if (mClassName == CLASS_ELLIPSE) {
|
||||
return RNSVGEllipseShadowNode.class;
|
||||
} else if (mClassName == CLASS_LINE) {
|
||||
return RNSVGLineShadowNode.class;
|
||||
} else if (mClassName == CLASS_RECT) {
|
||||
return RNSVGRectShadowNode.class;
|
||||
} else if (mClassName == CLASS_TEXT) {
|
||||
return RNSVGTextShadowNode.class;
|
||||
} else if (mClassName == CLASS_IMAGE) {
|
||||
return RNSVGImageShadowNode.class;
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected type " + mClassName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View createViewInstance(ThemedReactContext reactContext) {
|
||||
throw new IllegalStateException("RNSVGPath does not map into a native view");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateExtraData(View root, Object extraData) {
|
||||
throw new IllegalStateException("RNSVGPath does not map into a native view");
|
||||
protected ViewGroup createViewInstance(ThemedReactContext reactContext) {
|
||||
return new RNSVGRenderableView(reactContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,15 +14,43 @@ import javax.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
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 android.widget.FrameLayout;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.common.SystemClock;
|
||||
import com.facebook.react.touch.OnInterceptTouchEventListener;
|
||||
import com.facebook.react.touch.ReactInterceptingViewGroup;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.TouchTargetHelper;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.events.TouchEvent;
|
||||
import com.facebook.react.uimanager.events.TouchEventType;
|
||||
import com.facebook.react.views.view.ReactClippingViewGroup;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.react.uimanager.events.NativeGestureUtil;
|
||||
|
||||
// NativeGestureUtil.notifyNativeGestureStarted
|
||||
/**
|
||||
* Custom {@link View} implementation that draws an RNSVGSvg React view and its children.
|
||||
* Custom {@link View} implementation that draws an RNSVGSvg React view and its \children.
|
||||
*/
|
||||
public class RNSVGSvgView extends View {
|
||||
public class RNSVGSvgView extends ViewGroup {
|
||||
|
||||
private @Nullable Bitmap mBitmap;
|
||||
|
||||
private RNSVGSvgViewShadowNode mSvgViewShadowNode;
|
||||
|
||||
private int mTargetTag;
|
||||
|
||||
public RNSVGSvgView(Context context, RNSVGSvgViewShadowNode shadowNode) {
|
||||
super(context);
|
||||
mSvgViewShadowNode = shadowNode;
|
||||
}
|
||||
|
||||
public RNSVGSvgView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
@@ -42,4 +70,113 @@ public class RNSVGSvgView extends View {
|
||||
canvas.drawBitmap(mBitmap, 0, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent event) {
|
||||
mTargetTag = mSvgViewShadowNode.hitTest(new Point((int) event.getX(), (int) event.getY()), this);
|
||||
if (mTargetTag != -1) {
|
||||
EventDispatcher eventDispatcher = ((ThemedReactContext) this.getContext()).getNativeModule(UIManagerModule.class).getEventDispatcher();
|
||||
handleTouchEvent(event, eventDispatcher);
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.dispatchTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
|
||||
}
|
||||
|
||||
public void handleTouchEvent(MotionEvent ev, EventDispatcher eventDispatcher) {
|
||||
int action = ev.getAction() & MotionEvent.ACTION_MASK;
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
eventDispatcher.dispatchEvent(
|
||||
TouchEvent.obtain(
|
||||
mTargetTag,
|
||||
SystemClock.nanoTime(),
|
||||
TouchEventType.START,
|
||||
ev,
|
||||
ev.getX(),
|
||||
ev.getX()));
|
||||
} 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.
|
||||
eventDispatcher.dispatchEvent(
|
||||
TouchEvent.obtain(
|
||||
mTargetTag,
|
||||
SystemClock.nanoTime(),
|
||||
TouchEventType.END,
|
||||
ev,
|
||||
ev.getX(),
|
||||
ev.getY()));
|
||||
mTargetTag = -1;
|
||||
} else if (action == MotionEvent.ACTION_MOVE) {
|
||||
// Update pointer position for current gesture
|
||||
eventDispatcher.dispatchEvent(
|
||||
TouchEvent.obtain(
|
||||
mTargetTag,
|
||||
SystemClock.nanoTime(),
|
||||
TouchEventType.MOVE,
|
||||
ev,
|
||||
ev.getX(),
|
||||
ev.getY()));
|
||||
} else if (action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
// New pointer goes down, this can only happen after ACTION_DOWN is sent for the first pointer
|
||||
eventDispatcher.dispatchEvent(
|
||||
TouchEvent.obtain(
|
||||
mTargetTag,
|
||||
SystemClock.nanoTime(),
|
||||
TouchEventType.START,
|
||||
ev,
|
||||
ev.getX(),
|
||||
ev.getY()));
|
||||
} else if (action == MotionEvent.ACTION_POINTER_UP) {
|
||||
// Exactly onw of the pointers goes up
|
||||
eventDispatcher.dispatchEvent(
|
||||
TouchEvent.obtain(
|
||||
mTargetTag,
|
||||
SystemClock.nanoTime(),
|
||||
TouchEventType.END,
|
||||
ev,
|
||||
ev.getX(),
|
||||
ev.getY()));
|
||||
} else if (action == MotionEvent.ACTION_CANCEL) {
|
||||
dispatchCancelEvent(ev, eventDispatcher);
|
||||
mTargetTag = -1;
|
||||
} else {
|
||||
Log.w(
|
||||
"IGNORE",
|
||||
"Warning : touch event was ignored. Action=" + action + " Target=" + mTargetTag);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchCancelEvent(MotionEvent androidEvent, EventDispatcher eventDispatcher) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
Assertions.assertNotNull(eventDispatcher).dispatchEvent(
|
||||
TouchEvent.obtain(
|
||||
mTargetTag,
|
||||
SystemClock.nanoTime(),
|
||||
TouchEventType.CANCEL,
|
||||
androidEvent,
|
||||
androidEvent.getX(),
|
||||
androidEvent.getY()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,27 +10,27 @@
|
||||
package com.horcrux.svg;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.csslayout.CSSNode;
|
||||
import com.facebook.csslayout.MeasureOutput;
|
||||
import com.facebook.react.uimanager.BaseViewManager;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.ViewGroupManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* ViewManager for RNSVGSvgView React views. Renders as a {@link RNSVGSvgView} and handles
|
||||
* invalidating the native view on shadow view updates happening in the underlying tree.
|
||||
*/
|
||||
public class RNSVGSvgViewManager extends
|
||||
BaseViewManager<RNSVGSvgView, RNSVGSvgViewShadowNode> {
|
||||
public class RNSVGSvgViewManager extends ViewGroupManager<RNSVGSvgView> {
|
||||
|
||||
private static final String REACT_CLASS = "RNSVGSvgView";
|
||||
|
||||
private static final CSSNode.MeasureFunction MEASURE_FUNCTION = new CSSNode.MeasureFunction() {
|
||||
@Override
|
||||
public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) {
|
||||
throw new IllegalStateException("SvgView should have explicit width and height set");
|
||||
}
|
||||
};
|
||||
// TODO: use an ArrayList to connect RNSVGSvgViewShadowNode with RNSVGSvgView, not sure if there will be a race condition.
|
||||
// TODO: find a better way to replace this
|
||||
private ArrayList<RNSVGSvgViewShadowNode> SvgShadowNodes = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -40,7 +40,7 @@ public class RNSVGSvgViewManager extends
|
||||
@Override
|
||||
public RNSVGSvgViewShadowNode createShadowNodeInstance() {
|
||||
RNSVGSvgViewShadowNode node = new RNSVGSvgViewShadowNode();
|
||||
node.setMeasureFunction(MEASURE_FUNCTION);
|
||||
SvgShadowNodes.add(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,9 @@ public class RNSVGSvgViewManager extends
|
||||
|
||||
@Override
|
||||
protected RNSVGSvgView createViewInstance(ThemedReactContext reactContext) {
|
||||
return new RNSVGSvgView(reactContext);
|
||||
RNSVGSvgViewShadowNode shadowNode = SvgShadowNodes.get(0);
|
||||
SvgShadowNodes.remove(0);
|
||||
return new RNSVGSvgView(reactContext, shadowNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,6 +12,9 @@ package com.horcrux.svg;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Point;
|
||||
import android.util.Log;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
import com.facebook.react.uimanager.UIViewOperationQueue;
|
||||
@@ -20,17 +23,6 @@ import com.facebook.react.uimanager.UIViewOperationQueue;
|
||||
* Shadow node for RNSVG virtual tree root - RNSVGSvgView
|
||||
*/
|
||||
public class RNSVGSvgViewShadowNode extends LayoutShadowNode {
|
||||
|
||||
@Override
|
||||
public boolean isVirtual() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVirtualAnchor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCollectExtraUpdates(UIViewOperationQueue uiUpdater) {
|
||||
super.onCollectExtraUpdates(uiUpdater);
|
||||
@@ -40,17 +32,35 @@ public class RNSVGSvgViewShadowNode extends LayoutShadowNode {
|
||||
private Object drawOutput() {
|
||||
// TODO(7255985): Use TextureView and pass Svg from the view to draw on it asynchronously
|
||||
// instead of passing the bitmap (which is inefficient especially in terms of memory usage)
|
||||
float width = (int) getLayoutWidth();
|
||||
float height = (int) getLayoutHeight();
|
||||
Bitmap bitmap = Bitmap.createBitmap(
|
||||
(int) getLayoutWidth(),
|
||||
(int) getLayoutHeight(),
|
||||
(int) width,
|
||||
(int) height,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
Paint paint = new Paint();
|
||||
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
RNSVGVirtualNode child = (RNSVGVirtualNode) getChildAt(i);
|
||||
child.setDimensions(width, height);
|
||||
child.draw(canvas, paint, 1f);
|
||||
child.markUpdateSeen();
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public int hitTest(Point point, ViewGroup view) {
|
||||
int count = getChildCount();
|
||||
int viewTag = -1;
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
viewTag = ((RNSVGVirtualNode) getChildAt(i)).hitTest(point, view.getChildAt(i));
|
||||
if (viewTag != -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return viewTag;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,14 +11,18 @@ package com.horcrux.svg;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
@@ -84,26 +88,26 @@ public class RNSVGTextShadowNode extends RNSVGPathShadowNode {
|
||||
RectF box = getBox(paint, text);
|
||||
|
||||
if (setupStrokePaint(paint, opacity, box)) {
|
||||
applyTextPropertiesToPaint(paint);
|
||||
if (mPath == null) {
|
||||
canvas.drawText(text, 0, -paint.ascent(), paint);
|
||||
} else {
|
||||
canvas.drawTextOnPath(text, mPath, 0, -paint.ascent(), paint);
|
||||
}
|
||||
drawText(canvas, paint, text);
|
||||
}
|
||||
if (setupFillPaint(paint, opacity, box)) {
|
||||
applyTextPropertiesToPaint(paint);
|
||||
|
||||
if (mPath == null) {
|
||||
canvas.drawText(text, 0, -paint.ascent(), paint);
|
||||
} else {
|
||||
canvas.drawTextOnPath(text, mPath, 0, -paint.ascent(), paint);
|
||||
}
|
||||
drawText(canvas, paint, text);
|
||||
}
|
||||
|
||||
restoreCanvas(canvas);
|
||||
markUpdateSeen();
|
||||
}
|
||||
|
||||
private void drawText(Canvas canvas, Paint paint, String text) {
|
||||
applyTextPropertiesToPaint(paint);
|
||||
|
||||
if (mPath == null) {
|
||||
canvas.drawText(text, 0, -paint.ascent(), paint);
|
||||
} else {
|
||||
canvas.drawTextOnPath(text, mPath, 0, -paint.ascent(), paint);
|
||||
}
|
||||
}
|
||||
|
||||
private String formatText() {
|
||||
if (mFrame == null || !mFrame.hasKey(PROP_LINES)) {
|
||||
return null;
|
||||
@@ -170,6 +174,8 @@ public class RNSVGTextShadowNode extends RNSVGPathShadowNode {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Path getPath(Canvas canvas, Paint paint) {
|
||||
Path path = new Path();
|
||||
|
||||
@@ -178,6 +184,7 @@ public class RNSVGTextShadowNode extends RNSVGPathShadowNode {
|
||||
return path;
|
||||
}
|
||||
|
||||
// TODO: get path while TextPath is set.
|
||||
if (setupFillPaint(paint, 1.0f, getBox(paint, text))) {
|
||||
applyTextPropertiesToPaint(paint);
|
||||
paint.getTextPath(text, 0, text.length(), 0, -paint.ascent(), path);
|
||||
@@ -186,4 +193,43 @@ public class RNSVGTextShadowNode extends RNSVGPathShadowNode {
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hitTest(Point point, View view) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(
|
||||
(int) mWidth,
|
||||
(int) mHeight,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
canvas.concat(mMatrix);
|
||||
|
||||
// todo clip detect
|
||||
|
||||
String text = formatText();
|
||||
if (text == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Paint paint = new Paint();
|
||||
clip(canvas, paint);
|
||||
setHitTestFill(paint);
|
||||
drawText(canvas, paint, text);
|
||||
|
||||
if (setHitTestStroke(paint)) {
|
||||
drawText(canvas, paint, text);
|
||||
}
|
||||
|
||||
canvas.setBitmap(bitmap);
|
||||
try {
|
||||
if (bitmap.getPixel(point.x, point.y) != 0) {
|
||||
return view.getId();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return -1;
|
||||
} finally {
|
||||
bitmap.recycle();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,19 +16,21 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder;
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.ReactShadowNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -36,18 +38,19 @@ import java.util.Map;
|
||||
* Base class for RNSVGView virtual nodes: {@link RNSVGGroupShadowNode}, {@link RNSVGPathShadowNode} and
|
||||
* indirectly for {@link RNSVGTextShadowNode}.
|
||||
*/
|
||||
public abstract class RNSVGVirtualNode extends ReactShadowNode {
|
||||
public abstract class RNSVGVirtualNode extends LayoutShadowNode {
|
||||
protected static Map<String, Path> CLIP_PATHS = new HashMap<>();
|
||||
|
||||
protected static final float MIN_OPACITY_FOR_DRAW = 0.01f;
|
||||
|
||||
private static final float[] sMatrixData = new float[9];
|
||||
private static final float[] sRawMatrix = new float[9];
|
||||
private @Nullable String mDefinedClipPathId;
|
||||
protected float mOpacity = 1f;
|
||||
protected @Nullable Matrix mMatrix = new Matrix();
|
||||
|
||||
private @Nullable String mDefinedClipPathId;
|
||||
protected @Nullable Path mClipPath;
|
||||
private @Nullable String mClipPathId;
|
||||
protected @Nullable String mClipPathId;
|
||||
private static final int PATH_TYPE_ARC = 4;
|
||||
private static final int PATH_TYPE_CLOSE = 1;
|
||||
private static final int PATH_TYPE_CURVETO = 3;
|
||||
@@ -62,15 +65,13 @@ public abstract class RNSVGVirtualNode extends ReactShadowNode {
|
||||
private boolean mClipRuleSet;
|
||||
private boolean mClipDataSet;
|
||||
|
||||
protected float mWidth = 0;
|
||||
protected float mHeight = 0;
|
||||
|
||||
public RNSVGVirtualNode() {
|
||||
mScale = DisplayMetricsHolder.getWindowDisplayMetrics().density;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVirtual() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract void draw(Canvas canvas, Paint paint, float opacity);
|
||||
|
||||
/**
|
||||
@@ -127,8 +128,8 @@ public abstract class RNSVGVirtualNode extends ReactShadowNode {
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "transform")
|
||||
public void setTransform(@Nullable ReadableArray transformArray) {
|
||||
@ReactProp(name = "trans")
|
||||
public void setTrans(@Nullable ReadableArray transformArray) {
|
||||
if (transformArray != null) {
|
||||
int matrixSize = PropHelper.toFloatArray(transformArray, sMatrixData);
|
||||
if (matrixSize == 6) {
|
||||
@@ -155,7 +156,6 @@ public abstract class RNSVGVirtualNode extends ReactShadowNode {
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
"clipRule " + mClipRule + " unrecognized");
|
||||
}
|
||||
|
||||
createPath(mClipData, mClipPath);
|
||||
}
|
||||
}
|
||||
@@ -204,7 +204,6 @@ public abstract class RNSVGVirtualNode extends ReactShadowNode {
|
||||
int i = 0;
|
||||
|
||||
while (i < data.length) {
|
||||
|
||||
int type = (int) data[i++];
|
||||
switch (type) {
|
||||
case PATH_TYPE_MOVETO:
|
||||
@@ -270,16 +269,23 @@ public abstract class RNSVGVirtualNode extends ReactShadowNode {
|
||||
}
|
||||
}
|
||||
|
||||
public void setDimensions(float width, float height) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
abstract public int hitTest(Point point, View view);
|
||||
|
||||
protected void defineClipPath(Path clipPath, String clipPathId) {
|
||||
CLIP_PATHS.put(clipPathId, clipPath);
|
||||
mDefinedClipPathId = clipPathId;
|
||||
}
|
||||
|
||||
abstract protected Path getPath(Canvas canvas, Paint paint);
|
||||
|
||||
protected void finalize() {
|
||||
if (mDefinedClipPathId != null) {
|
||||
CLIP_PATHS.remove(mDefinedClipPathId);
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected Path getPath(Canvas canvas, Paint paint);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user