Skip to content

Commit e6d5627

Browse files
feat: replace OnLayoutEvent with SvgOnLayoutEvent (#2738)
This PR creates `SvgOnLayoutEvent` and replaces usage of `OnLayoutEvent` for Android because React Native Android team will remove this event from their codebase in near future.
1 parent 719d3d8 commit e6d5627

24 files changed

+269
-22
lines changed

android/src/main/java/com/horcrux/svg/RenderableView.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import android.graphics.RectF;
2323
import android.graphics.Region;
2424
import android.view.ViewParent;
25+
import com.facebook.react.bridge.Arguments;
2526
import com.facebook.react.bridge.ColorPropConverter;
2627
import com.facebook.react.bridge.Dynamic;
2728
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
@@ -30,7 +31,9 @@
3031
import com.facebook.react.bridge.ReadableArray;
3132
import com.facebook.react.bridge.ReadableMap;
3233
import com.facebook.react.bridge.ReadableType;
34+
import com.facebook.react.bridge.WritableMap;
3335
import com.facebook.react.touch.ReactHitSlopView;
36+
import com.facebook.react.uimanager.events.RCTEventEmitter;
3437
import com.facebook.react.uimanager.PointerEvents;
3538
import java.lang.reflect.Field;
3639
import java.util.ArrayList;
@@ -98,6 +101,14 @@ public abstract class RenderableView extends VirtualView implements ReactHitSlop
98101
private @Nullable ArrayList<String> mAttributeList;
99102
private @Nullable RenderableView mCaller;
100103

104+
public void onReceiveNativeEvent() {
105+
WritableMap event = Arguments.createMap();
106+
ReactContext reactContext = (ReactContext)getContext();
107+
reactContext
108+
.getJSModule(RCTEventEmitter.class)
109+
.receiveEvent(getId(), "topSvgLayout", event);
110+
}
111+
101112
@Nullable String mFilter;
102113

103114
private static final Pattern regex = Pattern.compile("[0-9.-]+");

android/src/main/java/com/horcrux/svg/RenderableViewManager.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@
142142
import com.facebook.react.viewmanagers.RNSVGUseManagerDelegate;
143143
import com.facebook.react.viewmanagers.RNSVGUseManagerInterface;
144144
import com.horcrux.svg.events.SvgLoadEvent;
145+
import com.horcrux.svg.events.SvgOnLayoutEvent;
145146
import java.util.HashMap;
146147
import java.util.Locale;
147148
import java.util.Map;
@@ -589,6 +590,12 @@ class RenderableViewManager<T extends RenderableView> extends VirtualViewManager
589590
super(svgclass);
590591
}
591592

593+
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
594+
Map<String, Object> eventTypes = new HashMap<>();
595+
eventTypes.put(SvgOnLayoutEvent.EVENT_NAME, MapBuilder.of("registrationName", "onSvgLayout"));
596+
return eventTypes;
597+
}
598+
592599
static class GroupViewManagerAbstract<U extends GroupView> extends RenderableViewManager<U> {
593600
GroupViewManagerAbstract(SVGClass svgClass) {
594601
super(svgClass);

android/src/main/java/com/horcrux/svg/VirtualView.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@
2020
import com.facebook.react.bridge.ReadableType;
2121
import com.facebook.react.common.ReactConstants;
2222
import com.facebook.react.uimanager.DisplayMetricsHolder;
23-
import com.facebook.react.uimanager.OnLayoutEvent;
2423
import com.facebook.react.uimanager.PointerEvents;
2524
import com.facebook.react.uimanager.UIManagerHelper;
2625
import com.facebook.react.uimanager.events.EventDispatcher;
2726
import com.facebook.react.views.view.ReactViewGroup;
27+
import com.horcrux.svg.events.SvgOnLayoutEvent;
28+
2829
import java.util.ArrayList;
2930
import javax.annotation.Nullable;
3031

@@ -603,7 +604,14 @@ void setClientRect(RectF rect) {
603604
EventDispatcher eventDispatcher =
604605
UIManagerHelper.getEventDispatcherForReactTag(mContext, getId());
605606
if (eventDispatcher != null) {
606-
eventDispatcher.dispatchEvent(OnLayoutEvent.obtain(this.getId(), left, top, width, height));
607+
eventDispatcher.dispatchEvent(
608+
new SvgOnLayoutEvent(
609+
UIManagerHelper.getSurfaceId(VirtualView.this),
610+
this.getId(),
611+
left,
612+
top,
613+
width,
614+
height));
607615
}
608616
}
609617

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.horcrux.svg.events;
2+
3+
import androidx.core.util.Pools.SynchronizedPool;
4+
5+
import com.facebook.react.bridge.Arguments;
6+
import com.facebook.react.bridge.WritableMap;
7+
import com.facebook.react.uimanager.PixelUtil;
8+
import com.facebook.react.uimanager.events.Event;
9+
10+
public class SvgOnLayoutEvent extends Event<SvgOnLayoutEvent> {
11+
12+
public static final String EVENT_NAME = "topSvgLayout";
13+
public int x = 0;
14+
public int y = 0;
15+
public int width = 0;
16+
public int height = 0;
17+
18+
public SvgOnLayoutEvent(int surfaceId, int viewId, int x, int y, int width, int height) {
19+
super(surfaceId, viewId);
20+
this.x = x;
21+
this.y = y;
22+
this.width = width;
23+
this.height = height;
24+
}
25+
26+
@Override
27+
public String getEventName() {
28+
return EVENT_NAME;
29+
}
30+
31+
@Override
32+
public short getCoalescingKey() {
33+
return 0;
34+
}
35+
36+
@Override
37+
protected WritableMap getEventData() {
38+
WritableMap layout = Arguments.createMap();
39+
layout.putDouble("x", (double) PixelUtil.toDIPFromPixel((float) x));
40+
layout.putDouble("y", (double) PixelUtil.toDIPFromPixel((float) y));
41+
layout.putDouble("width", (double) PixelUtil.toDIPFromPixel((float) width));
42+
layout.putDouble("height", (double) PixelUtil.toDIPFromPixel((float) height));
43+
44+
WritableMap event = Arguments.createMap();
45+
event.putMap("layout", layout);
46+
event.putInt("target", getViewTag());
47+
48+
return event;
49+
}
50+
}

apple/RNSVGNode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
6262
@property (nonatomic, assign) CGRect fillBounds;
6363
@property (nonatomic, assign) CGRect strokeBounds;
6464
@property (nonatomic, assign) CGRect markerBounds;
65-
@property (nonatomic, copy) RCTDirectEventBlock onLayout;
65+
@property (nonatomic, copy) RCTDirectEventBlock onSvgLayout;
6666

6767
/**
6868
* RNSVGSvgView which ownes current RNSVGNode

apple/RNSVGNode.mm

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
#import "RNSVGGlyphContext.h"
1313
#import "RNSVGGroup.h"
1414

15+
#ifdef RCT_NEW_ARCH_ENABLED
16+
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
17+
using namespace facebook::react;
18+
#endif // RCT_NEW_ARCH_ENABLED
19+
1520
@interface RNSVGNode ()
1621
@property (nonatomic, readwrite, weak) RNSVGSvgView *svgView;
1722
@property (nonatomic, readwrite, weak) RNSVGGroup *textRoot;
@@ -264,16 +269,18 @@ - (void)setClientRect:(CGRect)clientRect
264269
_clientRect = clientRect;
265270
#ifdef RCT_NEW_ARCH_ENABLED
266271
if (_eventEmitter != nullptr) {
267-
facebook::react::LayoutMetrics customLayoutMetrics = _layoutMetrics;
268-
customLayoutMetrics.frame.size.width = _clientRect.size.width;
269-
customLayoutMetrics.frame.size.height = _clientRect.size.height;
270-
customLayoutMetrics.frame.origin.x = _clientRect.origin.x;
271-
customLayoutMetrics.frame.origin.y = _clientRect.origin.y;
272-
_eventEmitter->onLayout(customLayoutMetrics);
272+
static_cast<const RNSVGGroupEventEmitter &>(*_eventEmitter)
273+
.onSvgLayout(
274+
{.layout = {
275+
.x = static_cast<int>(_clientRect.origin.x),
276+
.y = static_cast<int>(_clientRect.origin.y),
277+
.width = static_cast<int>(_clientRect.size.width),
278+
.height = static_cast<int>(_clientRect.size.height)
279+
}});
273280
}
274281
#else
275-
if (self.onLayout) {
276-
self.onLayout(@{
282+
if (self.onSvgLayout) {
283+
self.onSvgLayout(@{
277284
@"layout" : @{
278285
@"x" : @(_clientRect.origin.x),
279286
@"y" : @(_clientRect.origin.y),
@@ -660,7 +667,7 @@ - (void)prepareForRecycle
660667
_fillBounds = CGRectZero;
661668
_strokeBounds = CGRectZero;
662669
_markerBounds = CGRectZero;
663-
_onLayout = nil;
670+
_onSvgLayout = nil;
664671

665672
_svgView = nil;
666673
_textRoot = nil;

apple/ViewManagers/RNSVGNodeManager.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ - (RNSVGPlatformView *)view
4141
RCT_EXPORT_VIEW_PROPERTY(clipPath, NSString)
4242
RCT_EXPORT_VIEW_PROPERTY(clipRule, RNSVGCGFCRule)
4343
RCT_EXPORT_VIEW_PROPERTY(responsible, BOOL)
44-
RCT_EXPORT_VIEW_PROPERTY(onLayout, RCTDirectEventBlock)
44+
RCT_EXPORT_VIEW_PROPERTY(onSvgLayout, RCTDirectEventBlock)
4545

4646
RCT_CUSTOM_SHADOW_PROPERTY(top, id, RNSVGNode) {}
4747
RCT_CUSTOM_SHADOW_PROPERTY(right, id, RNSVGNode) {}

src/elements/Svg.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,6 @@ export default class Svg extends Shape<SvgProps> {
177177

178178
extractResponder(props, props, this as ResponderInstanceProps);
179179

180-
if (onLayout != null) {
181-
props.onLayout = onLayout;
182-
}
183-
184180
const gStyle = Object.assign({}, StyleSheet.flatten(style));
185181
if (transform) {
186182
if (gStyle.transform) {
@@ -214,6 +210,7 @@ export default class Svg extends Shape<SvgProps> {
214210
strokeLinecap,
215211
strokeLinejoin,
216212
strokeMiterlimit,
213+
onLayout,
217214
}}
218215
/>
219216
</RNSVGSvg>

src/fabric/CircleNativeComponent.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
22
import type { ColorValue } from 'react-native';
33
import type {
4+
DirectEventHandler,
45
Float,
56
Int32,
67
WithDefault,
@@ -31,6 +32,15 @@ type ColorStruct = Readonly<{
3132
brushRef?: string;
3233
}>;
3334

35+
type OnSvgLayoutEvent = Readonly<{
36+
layout: {
37+
x: Int32;
38+
y: Int32;
39+
width: Int32;
40+
height: Int32;
41+
};
42+
}>;
43+
3444
interface SvgRenderableCommonProps {
3545
color?: ColorValue;
3646
fill?: UnsafeMixed<ColorValue | ColorStruct>;
@@ -56,6 +66,7 @@ interface NativeProps
5666
cx?: UnsafeMixed<NumberProp>;
5767
cy?: UnsafeMixed<NumberProp>;
5868
r?: UnsafeMixed<NumberProp>;
69+
onSvgLayout?: DirectEventHandler<OnSvgLayoutEvent>;
5970
}
6071

6172
export default codegenNativeComponent<NativeProps>('RNSVGCircle', {

src/fabric/ClipPathNativeComponent.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
22
import type { ColorValue } from 'react-native';
33
import type {
4+
DirectEventHandler,
45
Float,
56
Int32,
67
WithDefault,
@@ -31,6 +32,15 @@ type ColorStruct = Readonly<{
3132
brushRef?: string;
3233
}>;
3334

35+
type OnSvgLayoutEvent = Readonly<{
36+
layout: {
37+
x: Int32;
38+
y: Int32;
39+
width: Int32;
40+
height: Int32;
41+
};
42+
}>;
43+
3444
interface SvgRenderableCommonProps {
3545
color?: ColorValue;
3646
fill?: UnsafeMixed<ColorValue | ColorStruct>;
@@ -59,7 +69,9 @@ interface NativeProps
5969
extends ViewProps,
6070
SvgNodeCommonProps,
6171
SvgRenderableCommonProps,
62-
SvgGroupCommonProps {}
72+
SvgGroupCommonProps {
73+
onSvgLayout?: DirectEventHandler<OnSvgLayoutEvent>;
74+
}
6375

6476
export default codegenNativeComponent<NativeProps>('RNSVGClipPath', {
6577
interfaceOnly: true,

0 commit comments

Comments
 (0)