From 857b5f52073ea83c15a42be6fc2a269b972c1945 Mon Sep 17 00:00:00 2001 From: Horcrux Date: Thu, 11 Aug 2016 16:27:15 +0800 Subject: [PATCH] Fix Image not rendering the first time svg is displayed Fix Image not rendering the first time svg is displayed Add toDataURL method for Svg elements for Android (not finished yet) --- Example/examples/Svg.js | 5 +- .../com/horcrux/svg/RNSVGImageShadowNode.java | 5 +- .../java/com/horcrux/svg/RNSVGSvgView.java | 10 +-- .../com/horcrux/svg/RNSVGSvgViewManager.java | 67 +++++++++++++++---- .../horcrux/svg/RNSVGSvgViewShadowNode.java | 30 ++++----- ios/ViewManagers/RNSVGSvgViewManager.m | 8 +-- 6 files changed, 81 insertions(+), 44 deletions(-) diff --git a/Example/examples/Svg.js b/Example/examples/Svg.js index 3ec6ee17..e746d04d 100644 --- a/Example/examples/Svg.js +++ b/Example/examples/Svg.js @@ -1,8 +1,7 @@ import { StyleSheet, View, - Image, - Text + Image } from 'react-native'; import React, { @@ -152,6 +151,7 @@ class SvgLayout extends Component{ } class SvgNativeMethods extends Component { + static title = 'Tap the shapes to render the Image below based on the base64-data of the Svg'; constructor() { super(...arguments); this.state = { @@ -174,7 +174,6 @@ class SvgNativeMethods extends Component { - Tap the shapes to render the Image below based on the base64-data of the Svg { private static final String REACT_CLASS = "RNSVGSvgView"; - private RNSVGSvgView svgView = null; - // 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 SvgShadowNodes = new ArrayList<>(); + private ArrayList mSvgShadowNodes = new ArrayList<>(); + + public static final int COMMAND_TO_DATA_URL = 100; @Override public String getName() { return REACT_CLASS; } - @Nullable - public RNSVGSvgView getSvgView() { - return this.svgView; + @Override + public @Nullable Map getCommandsMap() { + Map commandsMap = super.getCommandsMap(); + if (commandsMap == null) { + commandsMap = new HashMap<>(); + } + + commandsMap.put("toDataURL", COMMAND_TO_DATA_URL); + return commandsMap; } + @Override + public void receiveCommand(RNSVGSvgView root, int commandId, @Nullable ReadableArray args) { + super.receiveCommand(root, commandId, args); + + switch (commandId) { + case COMMAND_TO_DATA_URL: + toDataURL(root); + break; + } + } + + private void toDataURL(RNSVGSvgView root) { + WritableMap event = Arguments.createMap(); + event.putString("message", "MyMessage"); + ReactContext reactContext = (ReactContext)root.getContext(); + reactContext.getJSModule(RCTEventEmitter.class).receiveEvent( + root.getId(), + "onDataURL", + event); + } + + @Override public RNSVGSvgViewShadowNode createShadowNodeInstance() { - RNSVGSvgViewShadowNode node = new RNSVGSvgViewShadowNode(this); - SvgShadowNodes.add(node); + RNSVGSvgViewShadowNode node = new RNSVGSvgViewShadowNode(); + mSvgShadowNodes.add(node); return node; } @@ -55,10 +99,9 @@ public class RNSVGSvgViewManager extends ViewGroupManager { @Override protected RNSVGSvgView createViewInstance(ThemedReactContext reactContext) { - RNSVGSvgViewShadowNode shadowNode = SvgShadowNodes.get(0); - SvgShadowNodes.remove(0); - this.svgView = new RNSVGSvgView(reactContext, shadowNode); - return this.svgView; + RNSVGSvgView svgView = new RNSVGSvgView(reactContext); + svgView.setShadowNode(mSvgShadowNodes.remove(0)); + return svgView; } @Override diff --git a/android/src/main/java/com/horcrux/svg/RNSVGSvgViewShadowNode.java b/android/src/main/java/com/horcrux/svg/RNSVGSvgViewShadowNode.java index ac46c588..3ed3bc9d 100644 --- a/android/src/main/java/com/horcrux/svg/RNSVGSvgViewShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/RNSVGSvgViewShadowNode.java @@ -14,11 +14,13 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; +import android.util.Log; import android.view.View; import android.view.ViewGroup; import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.react.uimanager.LayoutShadowNode; +import com.facebook.react.uimanager.ReactShadowNode; import com.facebook.react.uimanager.UIViewOperationQueue; import java.util.HashMap; @@ -32,17 +34,11 @@ import javax.annotation.Nonnull; public class RNSVGSvgViewShadowNode extends LayoutShadowNode { private boolean mResponsible = false; + private RNSVGSvgView mSvgView; private static final Map mDefinedClipPaths = new HashMap<>(); private static final Map mDefinedTemplates = new HashMap<>(); private static final Map mDefinedBrushes = new HashMap<>(); - @Nonnull private final RNSVGSvgViewManager viewManager; - - public RNSVGSvgViewShadowNode(@Nonnull final RNSVGSvgViewManager viewManager) { - super(); - this.viewManager = viewManager; - } - @Override public void onCollectExtraUpdates(UIViewOperationQueue uiUpdater) { super.onCollectExtraUpdates(uiUpdater); @@ -88,16 +84,6 @@ public class RNSVGSvgViewShadowNode extends LayoutShadowNode { } } - protected void invalidateView(@Nonnull final Rect dirtyRect) { - final RNSVGSvgView svgView = this.viewManager.getSvgView(); - if (svgView != null) { - final View rootView = svgView.getRootView(); - if (rootView != null) { - rootView.invalidate(dirtyRect); - } - } - } - public void enableTouchEvents() { if (!mResponsible) { mResponsible = true; @@ -145,7 +131,15 @@ public class RNSVGSvgViewShadowNode extends LayoutShadowNode { mDefinedBrushes.put(brushRef, brush); } - public PropHelper.RNSVGBrush getDefinedBrush(String brushRef) { + public PropHelper.RNSVGBrush getDefinedBrush(String brushRef) { return mDefinedBrushes.get(brushRef); } + + public void setSvgView(RNSVGSvgView svgView) { + mSvgView = svgView; + } + + protected void invalidateView() { + mSvgView.invalidate(); + } } diff --git a/ios/ViewManagers/RNSVGSvgViewManager.m b/ios/ViewManagers/RNSVGSvgViewManager.m index 3636cb51..774e81a8 100644 --- a/ios/ViewManagers/RNSVGSvgViewManager.m +++ b/ios/ViewManagers/RNSVGSvgViewManager.m @@ -24,12 +24,12 @@ RCT_EXPORT_MODULE() RCT_EXPORT_METHOD(toDataURL:(nonnull NSNumber *)reactTag callback:(RCTResponseSenderBlock)callback) { [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { - UIView *view = viewRegistry[reactTag]; - if (![view isKindOfClass:[RNSVGSvgView class]]) { - RCTLogError(@"Invalid svg returned frin registry, expecting RNSVGSvgView, got: %@", view); - } else { + __kindof UIView *view = viewRegistry[reactTag]; + if ([view isKindOfClass:[RNSVGSvgView class]]) { RNSVGSvgView *svg = view; callback(@[[svg getDataURL]]); + } else { + RCTLogError(@"Invalid svg returned frin registry, expecting RNSVGSvgView, got: %@", view); } }]; }