Include non-virtual nodes when collecting NodeRegions

Summary: Before this patch, we only collected virtual nodes in NodeRegions, because NodeRegions are only needed to implement ReactCompoundView.reactTargetForTouch() which is only interested in virtual nodes. In the next patch, FlatViewGroup will implement ReactCompoundViewGroup interface which requires knowledge of both virtual and non-virtual children. As a step towards that, we need to include non-virtual nodes in NodeRegions. This patch is implementing that. By itself, it should have not cause any changes in application behavior: we add non-virtual nodes to NodeRegions and mark them as non-virtual, then skip all non-virtual nodes in reactTagForTouch().

Reviewed By: ahmedre

Differential Revision: D3018047
This commit is contained in:
Denis Koroskin 2016-03-07 20:06:31 -08:00 committed by Ahmed El-Helw
parent 8014147013
commit b52928c484
6 changed files with 56 additions and 21 deletions

View File

@ -251,10 +251,15 @@ import com.facebook.react.uimanager.annotations.ReactProp;
mNodeRegions = nodeRegion;
}
/* package */ void updateNodeRegion(float left, float top, float right, float bottom) {
if (mNodeRegion.mLeft != left || mNodeRegion.mTop != top ||
mNodeRegion.mRight != right || mNodeRegion.mBottom != bottom) {
setNodeRegion(new NodeRegion(left, top, right, bottom, getReactTag()));
/* package */ void updateNodeRegion(
float left,
float top,
float right,
float bottom,
boolean isVirtual) {
if (mNodeRegion.mLeft != left || mNodeRegion.mTop != top || mNodeRegion.mRight != right ||
mNodeRegion.mBottom != bottom || mNodeRegion.mIsVirtual != isVirtual) {
setNodeRegion(new NodeRegion(left, top, right, bottom, getReactTag(), isVirtual));
}
}

View File

@ -123,7 +123,7 @@ import com.facebook.react.views.image.ImageLoadEvent;
"TouchTargetHelper should not allow calling this method when pointer events are NONE");
if (mPointerEvents != PointerEvents.BOX_ONLY) {
NodeRegion nodeRegion = nodeRegionWithinBounds(touchX, touchY);
NodeRegion nodeRegion = virtualNodeRegionWithinBounds(touchX, touchY);
if (nodeRegion != null) {
return nodeRegion.getReactTag(touchX, touchY);
}
@ -277,7 +277,7 @@ import com.facebook.react.views.image.ImageLoadEvent;
if (mPointerEvents == PointerEvents.BOX_NONE) {
// We cannot always return false here because some child nodes could be flatten into this View
NodeRegion nodeRegion = nodeRegionWithinBounds(ev.getX(), ev.getY());
NodeRegion nodeRegion = virtualNodeRegionWithinBounds(ev.getX(), ev.getY());
if (nodeRegion == null) {
// no child to handle this touch event, bailing out.
return false;
@ -411,9 +411,13 @@ import com.facebook.react.views.image.ImageLoadEvent;
LAYOUT_REQUESTS.clear();
}
private NodeRegion nodeRegionWithinBounds(float touchX, float touchY) {
private NodeRegion virtualNodeRegionWithinBounds(float touchX, float touchY) {
for (int i = mNodeRegions.length - 1; i >= 0; --i) {
NodeRegion nodeRegion = mNodeRegions[i];
if (!nodeRegion.mIsVirtual) {
// only interested in virtual nodes
continue;
}
if (nodeRegion.withinBounds(touchX, touchY)) {
return nodeRegion;
}

View File

@ -11,20 +11,28 @@ package com.facebook.react.flat;
/* package */ class NodeRegion {
/* package */ static final NodeRegion[] EMPTY_ARRAY = new NodeRegion[0];
/* package */ static final NodeRegion EMPTY = new NodeRegion(0, 0, 0, 0, -1);
/* package */ static final NodeRegion EMPTY = new NodeRegion(0, 0, 0, 0, -1, false);
/* package */ final float mLeft;
/* package */ final float mTop;
/* package */ final float mRight;
/* package */ final float mBottom;
/* package */ final int mTag;
/* package */ final boolean mIsVirtual;
/* package */ NodeRegion(float left, float top, float right, float bottom, int tag) {
/* package */ NodeRegion(
float left,
float top,
float right,
float bottom,
int tag,
boolean isVirtual) {
mLeft = left;
mTop = top;
mRight = right;
mBottom = bottom;
mTag = tag;
mIsVirtual = isVirtual;
}
/* package */ final boolean withinBounds(float touchX, float touchY) {

View File

@ -223,9 +223,14 @@ import com.facebook.react.uimanager.annotations.ReactProp;
}
@Override
/* package */ void updateNodeRegion(float left, float top, float right, float bottom) {
/* package */ void updateNodeRegion(
float left,
float top,
float right,
float bottom,
boolean isVirtual) {
if (mDrawCommand == null) {
super.updateNodeRegion(left, top, right, bottom);
super.updateNodeRegion(left, top, right, bottom, isVirtual);
return;
}
@ -239,8 +244,9 @@ import com.facebook.react.uimanager.annotations.ReactProp;
Layout newLayout = mDrawCommand.getLayout();
if (nodeRegion.mLeft != left || nodeRegion.mTop != top ||
nodeRegion.mRight != right || nodeRegion.mBottom != bottom ||
layout != newLayout) {
setNodeRegion(new TextNodeRegion(left, top, right, bottom, getReactTag(), newLayout));
nodeRegion.mIsVirtual != isVirtual || layout != newLayout) {
setNodeRegion(
new TextNodeRegion(left, top, right, bottom, getReactTag(), isVirtual, newLayout));
}
}

View File

@ -197,13 +197,14 @@ import com.facebook.react.uimanager.events.EventDispatcher;
float left,
float top,
float right,
float bottom) {
float bottom,
boolean isVirtual) {
if (left == right || top == bottom) {
// no point in adding an empty NodeRegion
return;
}
node.updateNodeRegion(left, top, right, bottom);
node.updateNodeRegion(left, top, right, bottom, isVirtual);
mNodeRegions.add(node.getNodeRegion());
}
@ -291,7 +292,7 @@ import com.facebook.react.uimanager.events.EventDispatcher;
// FlatViewGroup.reactTagForTouch() will always return RCTText's id. To fix the issue,
// manually add nodeRegion so it will have exactly one NodeRegion, and virtual nodes will
// be able to receive touch events.
addNodeRegion(node, left, top, right, bottom);
addNodeRegion(node, left, top, right, bottom, true);
}
boolean descendantUpdated = collectStateRecursively(
@ -520,9 +521,15 @@ import com.facebook.react.uimanager.events.EventDispatcher;
float right = left + width;
float bottom = top + height;
boolean mountsToView = node.mountsToView();
final boolean updated;
if (node.mountsToView()) {
if (!parentIsAndroidView) {
addNodeRegion(node, left, top, right, bottom, !mountsToView);
}
if (mountsToView) {
ensureBackingViewIsCreated(node);
addNativeChild(node);
@ -549,8 +556,6 @@ import com.facebook.react.uimanager.events.EventDispatcher;
updateViewBounds(node, left, top, right, bottom);
}
} else {
addNodeRegion(node, left, top, right, bottom);
updated = collectStateRecursively(
node,
left,

View File

@ -15,8 +15,15 @@ import android.text.Spanned;
/* package */ final class TextNodeRegion extends NodeRegion {
private final Layout mLayout;
TextNodeRegion(float left, float top, float right, float bottom, int tag, Layout layout) {
super(left, top, right, bottom, tag);
/* package */ TextNodeRegion(
float left,
float top,
float right,
float bottom,
int tag,
boolean isVirtual,
Layout layout) {
super(left, top, right, bottom, tag, isVirtual);
mLayout = layout;
}