Add backward compatible support for onLayout event in Fabric

Reviewed By: achen1

Differential Revision: D8231722

fbshipit-source-id: 3d0641a7813e742ca81b98576f9ffc30ee597f30
This commit is contained in:
David Vacca
2018-06-01 17:47:40 -07:00
committed by Facebook Github Bot
parent 6c989fe7c6
commit 6aea98441a
8 changed files with 90 additions and 10 deletions

View File

@@ -10,6 +10,7 @@ package com.facebook.react.fabric;
import static android.view.View.MeasureSpec.AT_MOST;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.UNSPECIFIED;
import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;
import android.util.Log;
import android.view.View;
@@ -24,9 +25,11 @@ import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.fabric.events.FabricEventEmitter;
import com.facebook.react.modules.i18nmanager.I18nUtil;
import com.facebook.react.uimanager.DisplayMetricsHolder;
import com.facebook.react.uimanager.NativeViewHierarchyManager;
import com.facebook.react.uimanager.OnLayoutEvent;
import com.facebook.react.uimanager.ReactRootViewTagGenerator;
import com.facebook.react.uimanager.ReactShadowNode;
import com.facebook.react.uimanager.ReactShadowNodeImpl;
@@ -37,6 +40,7 @@ import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.uimanager.ViewManagerRegistry;
import com.facebook.react.uimanager.common.MeasureSpecProvider;
import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.yoga.YogaDirection;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -61,13 +65,15 @@ public class FabricUIManager implements UIManager, JSHandler {
private final JavaScriptContextHolder mJSContext;
private volatile int mCurrentBatch = 0;
private final FabricReconciler mFabricReconciler;
private final EventDispatcher mEventDispatcher;
private FabricBinding mBinding;
private long mEventHandlerPointer;
public FabricUIManager(
ReactApplicationContext reactContext,
ViewManagerRegistry viewManagerRegistry,
JavaScriptContextHolder jsContext) {
JavaScriptContextHolder jsContext,
EventDispatcher eventDispatcher) {
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext);
mReactApplicationContext = reactContext;
mViewManagerRegistry = viewManagerRegistry;
@@ -76,7 +82,12 @@ public class FabricUIManager implements UIManager, JSHandler {
new UIViewOperationQueue(
reactContext, mNativeViewHierarchyManager, 0);
mFabricReconciler = new FabricReconciler(mUIViewOperationQueue);
mEventDispatcher = eventDispatcher;
mJSContext = jsContext;
FabricEventEmitter eventEmitter =
new FabricEventEmitter(reactContext, this);
eventDispatcher.registerEventEmitter(FABRIC, eventEmitter);
}
public void setBinding(FabricBinding binding) {
@@ -355,7 +366,18 @@ public class FabricUIManager implements UIManager, JSHandler {
if (mRootShadowNodeRegistry.getNode(tag) == null) {
boolean frameDidChange =
node.dispatchUpdates(absoluteX, absoluteY, mUIViewOperationQueue, null);
// Notify JS about layout event if requested
// and if the position or dimensions actually changed
// (consistent with iOS and Android Default implementation).
if (frameDidChange && node.shouldNotifyOnLayout()) {
mUIViewOperationQueue.enqueueOnLayoutEvent(tag,
node.getScreenX(),
node.getScreenY(),
node.getScreenWidth(),
node.getScreenHeight());
}
}
// Set the reference to the OriginalReactShadowNode to NULL, as the tree is already committed
// and we do not need to hold references to the previous tree anymore
node.setOriginalReactShadowNode(null);

View File

@@ -26,6 +26,7 @@ import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.fabric.FabricUIManager;
import com.facebook.react.fabric.Scheduler;
import com.facebook.react.fabric.Work;
import com.facebook.react.uimanager.IllegalViewOperationException;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import java.io.Closeable;
import java.io.IOException;
@@ -48,9 +49,13 @@ public class FabricEventEmitter implements RCTEventEmitter, Closeable {
}
@Override
public void receiveEvent(int targetTag, String eventName, @Nullable WritableMap params) {
long eventTarget = mFabricUIManager.createEventTarget(targetTag);
mScheduler.scheduleWork(new FabricUIManagerWork(eventTarget, eventName, params));
public void receiveEvent(int reactTag, String eventName, @Nullable WritableMap params) {
try {
long eventTarget = mFabricUIManager.createEventTarget(reactTag);
mScheduler.scheduleWork(new FabricUIManagerWork(eventTarget, eventName, params));
} catch (IllegalViewOperationException e) {
Log.e(TAG, "Unable to emmit event for tag " + reactTag, e);
}
}
@Override

View File

@@ -224,11 +224,11 @@ public class NativeViewHierarchyManager {
public long getInstanceHandle(int reactTag) {
View view = mTagsToViews.get(reactTag);
if (view == null) {
throw new IllegalArgumentException("Unable to find view for tag: " + reactTag);
throw new IllegalViewOperationException("Unable to find view for tag: " + reactTag);
}
Long instanceHandle = (Long) view.getTag(R.id.view_tag_instance_handle);
if (instanceHandle == null) {
throw new IllegalArgumentException("Unable to find instanceHandle for tag: " + reactTag);
throw new IllegalViewOperationException("Unable to find instanceHandle for tag: " + reactTag);
}
return instanceHandle;
}

View File

@@ -96,6 +96,38 @@ public class UIViewOperationQueue {
}
}
private final class EmitOnLayoutEventOperation extends ViewOperation {
private final int mScreenX;
private final int mScreenY;
private final int mScreenWidth;
private final int mScreenHeight;
public EmitOnLayoutEventOperation(
int tag,
int screenX,
int screenY,
int screenWidth,
int screenHeight) {
super(tag);
mScreenX = screenX;
mScreenY = screenY;
mScreenWidth = screenWidth;
mScreenHeight = screenHeight;
}
@Override
public void execute() {
mReactApplicationContext.getNativeModule(UIManagerModule.class)
.getEventDispatcher()
.dispatchEvent(OnLayoutEvent.obtain(
mTag,
mScreenX,
mScreenY,
mScreenWidth,
mScreenHeight));
}
}
private final class UpdateInstanceHandleOperation extends ViewOperation {
@@ -706,6 +738,16 @@ public class UIViewOperationQueue {
mOperations.add(new UpdatePropertiesOperation(reactTag, props));
}
public void enqueueOnLayoutEvent(
int tag,
int screenX,
int screenY,
int screenWidth,
int screenHeight) {
mOperations.add(new EmitOnLayoutEventOperation(tag, screenX, screenY, screenWidth, screenHeight));
}
public void enqueueUpdateLayout(
int parentTag,
int reactTag,