Make FlatUIImplementation.measure() work with virtual views (shadow nodes that don't map to a View)

Summary: UIImplementation.measure() can only measure shadow nodes that map to native Views. As a result of this, every time we tried to measure a shadow node that doesn't map to a View, we trigger callback with no data (to indicate an error). To fix this issue, walk up until we find a node that maps to a View, then measure that View and adjust for the bounds of a virtual child.

Reviewed By: ahmedre

Differential Revision: D2800960
This commit is contained in:
Denis Koroskin 2016-01-05 12:58:43 -08:00 committed by Ahmed El-Helw
parent b321ea98d3
commit 05544f6bca
2 changed files with 103 additions and 0 deletions

View File

@ -16,6 +16,8 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.CatalystStylesDiffMap;
@ -151,6 +153,43 @@ public class FlatUIImplementation extends UIImplementation {
addChildren(parentNode, addChildTags, addAtIndices);
}
@Override
public void measure(int reactTag, Callback callback) {
FlatShadowNode node = (FlatShadowNode) resolveShadowNode(reactTag);
if (node.mountsToView()) {
super.measure(reactTag, callback);
return;
}
float width = node.getLayoutWidth();
float height = node.getLayoutHeight();
float xInParent = node.getLayoutX();
float yInParent = node.getLayoutY();
while (true) {
node = Assertions.assumeNotNull((FlatShadowNode) node.getParent());
if (node.mountsToView()) {
break;
}
xInParent += node.getLayoutX();
yInParent += node.getLayoutY();
}
float parentWidth = node.getLayoutWidth();
float parentHeight = node.getLayoutHeight();
FlatUIViewOperationQueue operationsQueue = mStateBuilder.getOperationsQueue();
operationsQueue.enqueueMeasureVirtualView(
node.getReactTag(),
xInParent / parentWidth,
yInParent / parentHeight,
width / parentWidth,
height / parentHeight,
callback);
}
/**
* Removes all children defined by moveFrom and removeFrom from a given parent,
* preparing elements in moveFrom to be re-added at proper index.

View File

@ -11,7 +11,9 @@ package com.facebook.react.flat;
import javax.annotation.Nullable;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.UIViewOperationQueue;
/**
@ -20,6 +22,8 @@ import com.facebook.react.uimanager.UIViewOperationQueue;
*/
/* package */ final class FlatUIViewOperationQueue extends UIViewOperationQueue {
private static final int[] MEASURE_BUFFER = new int[4];
private final FlatNativeViewHierarchyManager mNativeViewHierarchyManager;
private final ProcessLayoutRequests mProcessLayoutRequests = new ProcessLayoutRequests();
@ -150,6 +154,50 @@ import com.facebook.react.uimanager.UIViewOperationQueue;
}
}
private final class MeasureVirtualView implements UIOperation {
private final int mReactTag;
private final float mScaledX;
private final float mScaledY;
private final float mScaledWidth;
private final float mScaledHeight;
private final Callback mCallback;
private MeasureVirtualView(
int reactTag,
float scaledX,
float scaledY,
float scaledWidth,
float scaledHeight,
Callback callback) {
mReactTag = reactTag;
mScaledX = scaledX;
mScaledY = scaledY;
mScaledWidth = scaledWidth;
mScaledHeight = scaledHeight;
mCallback = callback;
}
@Override
public void execute() {
// Measure native View
mNativeViewHierarchyManager.measure(mReactTag, MEASURE_BUFFER);
float nativeViewX = MEASURE_BUFFER[0];
float nativeViewY = MEASURE_BUFFER[1];
float nativeViewWidth = MEASURE_BUFFER[2];
float nativeViewHeight = MEASURE_BUFFER[3];
// Calculate size of the virtual child inside native View.
float x = PixelUtil.toDIPFromPixel(mScaledX * nativeViewWidth + nativeViewX);
float y = PixelUtil.toDIPFromPixel(mScaledY * nativeViewHeight + nativeViewY);
float width = PixelUtil.toDIPFromPixel(mScaledWidth * nativeViewWidth);
float height = PixelUtil.toDIPFromPixel(mScaledHeight * nativeViewHeight);
mCallback.invoke(0, 0, width, height, x, y);
}
}
public final class DetachAllChildrenFromViews implements UIViewOperationQueue.UIOperation {
private @Nullable int[] mViewsToDetachAllChildrenFrom;
@ -207,6 +255,22 @@ import com.facebook.react.uimanager.UIViewOperationQueue;
enqueueUIOperation(new DropViews(viewsToDrop));
}
public void enqueueMeasureVirtualView(
int reactTag,
float scaledX,
float scaledY,
float scaledWidth,
float scaledHeight,
Callback callback) {
enqueueUIOperation(new MeasureVirtualView(
reactTag,
scaledX,
scaledY,
scaledWidth,
scaledHeight,
callback));
}
public void enqueueProcessLayoutRequests() {
enqueueUIOperation(mProcessLayoutRequests);
}