Permalink
Browse files

Fix touch target for views with z-index

Summary:
The new implementation of z-index did not handle touches properly. This fixes it by using the mapped child index like we do in `getChildDrawingOrder` in `TouchTargetHelper`.

**Test plan**
Tested that touchables work properly inside sticky headers (it uses z-index) on Android.
Closes #13705

Reviewed By: AaaChiuuu

Differential Revision: D4987964

Pulled By: sahrens

fbshipit-source-id: 165f98e23d2f304c4dc87f536c22b68a8923d806
  • Loading branch information...
janicduplessis authored and facebook-github-bot committed May 2, 2017
1 parent 7063261 commit 6f092a4264591d543a1afca981b31ce0287d9b28
@@ -0,0 +1,15 @@
// Copyright 2004-present Facebook. All Rights Reserved.
package com.facebook.react.uimanager;
/**
* ViewGroup that supports z-index.
*/
public interface ReactZIndexedViewGroup {
/**
* Determine the index of a child view at {@param index} considering z-index.
* @param index The child view index
* @return The child view index considering z-index
*/
int getZIndexMappedChildIndex(int index);
}
@@ -124,8 +124,13 @@ private static View findClosestReactAncestor(View view) {
*/
private static View findTouchTargetView(float[] eventCoords, ViewGroup viewGroup) {
int childrenCount = viewGroup.getChildCount();
// Consider z-index when determining the touch target.
ReactZIndexedViewGroup zIndexedViewGroup = viewGroup instanceof ReactZIndexedViewGroup ?
(ReactZIndexedViewGroup) viewGroup :
null;
for (int i = childrenCount - 1; i >= 0; i--) {
View child = viewGroup.getChildAt(i);
int childIndex = zIndexedViewGroup != null ? zIndexedViewGroup.getZIndexMappedChildIndex(i) : i;
View child = viewGroup.getChildAt(childIndex);
PointF childPoint = mTempPoint;
if (isTransformedTouchPointInView(eventCoords[0], eventCoords[1], viewGroup, child, childPoint)) {
// If it is contained within the child View, the childPoint value will contain the view
@@ -31,14 +31,16 @@
import com.facebook.react.uimanager.ReactClippingViewGroup;
import com.facebook.react.uimanager.ReactClippingViewGroupHelper;
import com.facebook.react.uimanager.ReactPointerEventsView;
import com.facebook.react.uimanager.ReactZIndexedViewGroup;
import com.facebook.react.uimanager.ViewGroupDrawingOrderHelper;
/**
* Backing for a React View. Has support for borders, but since borders aren't common, lazy
* initializes most of the storage needed for them.
*/
public class ReactViewGroup extends ViewGroup implements
ReactInterceptingViewGroup, ReactClippingViewGroup, ReactPointerEventsView, ReactHitSlopView {
ReactInterceptingViewGroup, ReactClippingViewGroup, ReactPointerEventsView, ReactHitSlopView,
ReactZIndexedViewGroup {
private static final int ARRAY_CAPACITY_INCREMENT = 12;
private static final int DEFAULT_BACKGROUND_COLOR = Color.TRANSPARENT;
@@ -408,6 +410,15 @@ protected int getChildDrawingOrder(int childCount, int index) {
return mDrawingOrderHelper.getChildDrawingOrder(childCount, index);
}
@Override
public int getZIndexMappedChildIndex(int index) {
if (mDrawingOrderHelper.shouldEnableCustomDrawingOrder()) {
return mDrawingOrderHelper.getChildDrawingOrder(getChildCount(), index);
} else {
return index;
}
}
@Override
public PointerEvents getPointerEvents() {
return mPointerEvents;

1 comment on commit 6f092a4

@jp928

This comment has been minimized.

Show comment
Hide comment
@jp928

jp928 Jun 15, 2017

could u plz explain a little bit more? if nested absolute positioned Views wrap a touchable*, how can I define zIndex to make the most inner touchable thing toichable? seems like some of my touchable things atop working since I upgrade to 0.45.1.

jp928 commented on 6f092a4 Jun 15, 2017

could u plz explain a little bit more? if nested absolute positioned Views wrap a touchable*, how can I define zIndex to make the most inner touchable thing toichable? seems like some of my touchable things atop working since I upgrade to 0.45.1.

Please sign in to comment.