Make FlatViewGroup implement ReactCompoundViewGroup interface

Summary: In FlatViewGroup, we flatten some react nodes into parent while mounting others into child Views. This is causing touch events being dispatched to wrong targets because child Views are \"stealing\" touch events from flattened Views. To fix the issue, implement ReactCompoundViewGroup to provide information about both virtual and non-virtual nodes.

Reviewed By: ahmedre

Differential Revision: D3018054
This commit is contained in:
Denis Koroskin 2016-03-07 20:06:32 -08:00 committed by Ahmed El-Helw
parent b52928c484
commit 89cf5c49b9
1 changed files with 28 additions and 3 deletions

View File

@ -29,7 +29,7 @@ import com.facebook.react.common.SystemClock;
import com.facebook.react.touch.OnInterceptTouchEventListener;
import com.facebook.react.touch.ReactInterceptingViewGroup;
import com.facebook.react.uimanager.PointerEvents;
import com.facebook.react.uimanager.ReactCompoundView;
import com.facebook.react.uimanager.ReactCompoundViewGroup;
import com.facebook.react.uimanager.ReactPointerEventsView;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.views.image.ImageLoadEvent;
@ -39,7 +39,7 @@ import com.facebook.react.views.image.ImageLoadEvent;
* array of DrawCommands, executing them one by one.
*/
/* package */ final class FlatViewGroup extends ViewGroup
implements ReactInterceptingViewGroup, ReactCompoundView, ReactPointerEventsView {
implements ReactInterceptingViewGroup, ReactCompoundViewGroup, ReactPointerEventsView {
/**
* Helper class that allows AttachDetachListener to invalidate the hosting View.
*/
@ -133,6 +133,16 @@ import com.facebook.react.views.image.ImageLoadEvent;
return getId();
}
@Override
public boolean interceptsTouchEvent(float touchX, float touchY) {
NodeRegion nodeRegion = anyNodeRegionWithinBounds(touchX, touchY);
if (nodeRegion != null) {
return nodeRegion.mIsVirtual;
}
return false;
}
@Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
@ -257,6 +267,10 @@ import com.facebook.react.views.image.ImageLoadEvent;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (interceptsTouchEvent(ev.getX(), ev.getY())) {
return true;
}
if (mOnInterceptTouchEventListener != null &&
mOnInterceptTouchEventListener.onInterceptTouchEvent(this, ev)) {
return true;
@ -411,7 +425,7 @@ import com.facebook.react.views.image.ImageLoadEvent;
LAYOUT_REQUESTS.clear();
}
private NodeRegion virtualNodeRegionWithinBounds(float touchX, float touchY) {
private @Nullable NodeRegion virtualNodeRegionWithinBounds(float touchX, float touchY) {
for (int i = mNodeRegions.length - 1; i >= 0; --i) {
NodeRegion nodeRegion = mNodeRegions[i];
if (!nodeRegion.mIsVirtual) {
@ -426,6 +440,17 @@ import com.facebook.react.views.image.ImageLoadEvent;
return null;
}
private @Nullable NodeRegion anyNodeRegionWithinBounds(float touchX, float touchY) {
for (int i = mNodeRegions.length - 1; i >= 0; --i) {
NodeRegion nodeRegion = mNodeRegions[i];
if (nodeRegion.withinBounds(touchX, touchY)) {
return nodeRegion;
}
}
return null;
}
private View ensureViewHasNoParent(View view) {
ViewParent oldParent = view.getParent();
if (oldParent != null) {