From c3b42869154f5058f4a35300ab69e8a0350f8d46 Mon Sep 17 00:00:00 2001 From: Seth Kirby Date: Thu, 11 Aug 2016 17:40:38 -0700 Subject: [PATCH] Implement hit slop. Summary: Hitslop on RTCView both virtual and non-virtual. Reviewed By: ahmedre Differential Revision: D3693412 --- .../facebook/react/flat/FlatViewGroup.java | 14 ++++++- .../com/facebook/react/flat/NodeRegion.java | 10 +++++ .../java/com/facebook/react/flat/RCTView.java | 39 +++++++++++++++++++ .../facebook/react/flat/RCTViewManager.java | 15 +++++++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatViewGroup.java b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatViewGroup.java index d90d91558..3b231d1e7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/FlatViewGroup.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/FlatViewGroup.java @@ -32,6 +32,7 @@ import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.SoftAssertions; import com.facebook.react.touch.OnInterceptTouchEventListener; +import com.facebook.react.touch.ReactHitSlopView; import com.facebook.react.touch.ReactInterceptingViewGroup; import com.facebook.react.uimanager.PointerEvents; import com.facebook.react.uimanager.ReactCompoundViewGroup; @@ -48,7 +49,7 @@ import com.facebook.react.views.view.ReactClippingViewGroup; */ /* package */ final class FlatViewGroup extends ViewGroup implements ReactInterceptingViewGroup, ReactClippingViewGroup, - ReactCompoundViewGroup, ReactPointerEventsView, FlatMeasuredViewGroup { + ReactCompoundViewGroup, ReactHitSlopView, ReactPointerEventsView, FlatMeasuredViewGroup { /** * Helper class that allows AttachDetachListener to invalidate the hosting View. */ @@ -109,6 +110,8 @@ import com.facebook.react.views.view.ReactClippingViewGroup; private static final ArrayList EMPTY_DETACHED_VIEWS = new ArrayList<>(0); private @Nullable DrawCommandManager mDrawCommandManager; + private @Nullable Rect mHitSlopRect; + /* package */ FlatViewGroup(Context context) { super(context); setClipChildren(false); @@ -911,4 +914,13 @@ import com.facebook.react.views.view.ReactClippingViewGroup; public boolean getRemoveClippedSubviews() { return mDrawCommandManager != null; } + + @Override + public @Nullable Rect getHitSlopRect() { + return mHitSlopRect; + } + + public void setHitSlopRect(@Nullable Rect rect) { + mHitSlopRect = rect; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/NodeRegion.java b/ReactAndroid/src/main/java/com/facebook/react/flat/NodeRegion.java index be20ab0a5..6279c7faa 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/NodeRegion.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/NodeRegion.java @@ -35,6 +35,16 @@ package com.facebook.react.flat; mIsVirtual = isVirtual; } + /* package */ final boolean matches( + float left, + float top, + float right, + float bottom, + boolean isVirtual) { + return left == mLeft && top == mTop && bottom == mBottom && right == mRight && + isVirtual == mIsVirtual; + } + /* package */ final boolean withinBounds(float touchX, float touchY) { return mLeft <= touchX && touchX < mRight && mTop <= touchY && touchY < mBottom; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTView.java b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTView.java index 33cf11ffd..9af44551c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTView.java @@ -11,6 +11,8 @@ package com.facebook.react.flat; import javax.annotation.Nullable; +import android.graphics.Rect; + import com.facebook.react.bridge.ReadableMap; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.ReactStylesDiffMap; @@ -18,6 +20,9 @@ import com.facebook.react.uimanager.ViewProps; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.annotations.ReactPropGroup; +/** + * Node for a react View. + */ /* package */ final class RCTView extends FlatShadowNode { private @Nullable DrawBorder mDrawBorder; @@ -25,6 +30,8 @@ import com.facebook.react.uimanager.annotations.ReactPropGroup; boolean mRemoveClippedSubviews; boolean mHorizontal; + private @Nullable Rect mHitSlop; + @Override /* package */ void handleUpdateProperties(ReactStylesDiffMap styles) { mRemoveClippedSubviews = mRemoveClippedSubviews || @@ -123,11 +130,43 @@ import com.facebook.react.uimanager.annotations.ReactPropGroup; getMutableBorder().setBorderStyle(borderStyle); } + @ReactProp(name = "hitSlop") + public void setHitSlop(@Nullable ReadableMap hitSlop) { + if (hitSlop == null) { + mHitSlop = null; + } else { + mHitSlop = new Rect( + (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("left")), + (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("top")), + (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("right")), + (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("bottom"))); + } + } + @ReactProp(name = "pointerEvents") public void setPointerEvents(@Nullable String pointerEventsStr) { forceMountToView(); } + @Override + /* package */ void updateNodeRegion( + float left, + float top, + float right, + float bottom, + boolean isVirtual) { + if (mHitSlop != null) { + left -= mHitSlop.left; + top -= mHitSlop.top; + bottom += mHitSlop.bottom; + right += mHitSlop.right; + } + + if (!getNodeRegion().matches(left, top, right, bottom, isVirtual)) { + setNodeRegion(new NodeRegion(left, top, right, bottom, getReactTag(), isVirtual)); + } + } + private DrawBorder getMutableBorder() { if (mDrawBorder == null) { mDrawBorder = new DrawBorder(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTViewManager.java index 1244669e4..b518c5d1e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/flat/RCTViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/flat/RCTViewManager.java @@ -13,6 +13,7 @@ import javax.annotation.Nullable; import java.util.Map; +import android.graphics.Rect; import android.os.Build; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; @@ -124,4 +125,18 @@ import com.facebook.react.views.view.ReactDrawableHelper; // default or invalid return PointerEvents.AUTO; } + + @ReactProp(name = "hitSlop") + public void setHitSlop(FlatViewGroup view, @Nullable ReadableMap hitSlop) { + if (hitSlop == null) { + view.setHitSlopRect(null); + } else { + view.setHitSlopRect(new Rect( + (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("left")), + (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("top")), + (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("right")), + (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("bottom")) + )); + } + } }