Separate Node bounds and hit bounds within node region where needed.

Summary: Node region bounds are assumed to equal the underlying node bounds.  In the case of hit slop, these need to be abstracted.

Reviewed By: ahmedre

Differential Revision: D3713430
This commit is contained in:
Seth Kirby
2016-08-16 11:26:27 -07:00
committed by Ahmed El-Helw
parent a602891946
commit 4a12efad02
9 changed files with 169 additions and 48 deletions

View File

@@ -187,9 +187,7 @@ import com.facebook.react.views.view.ReactClippingViewGroupHelper;
if (mountsToView()) {
return mViewRight - mViewLeft;
} else {
// this is not technically correct since hitSlop affects the NodeRegion, but it's a temporary
// work around for now, since mView{Right,Left} are only set for views
return Math.round(mNodeRegion.mRight - mNodeRegion.mLeft);
return Math.round(mNodeRegion.getRight() - mNodeRegion.getLeft());
}
}
@@ -198,9 +196,7 @@ import com.facebook.react.views.view.ReactClippingViewGroupHelper;
if (mountsToView()) {
return mViewBottom - mViewTop;
} else {
// this is not technically correct since hitSlop affects the NodeRegion, but it's a temporary
// work around for now, since mView{Bottom,Top} are only set for views
return Math.round(mNodeRegion.mBottom - mNodeRegion.mTop);
return Math.round(mNodeRegion.getBottom() - mNodeRegion.getTop());
}
}
@@ -332,8 +328,8 @@ import com.facebook.react.views.view.ReactClippingViewGroupHelper;
/* package */ final void updateOverflowsContainer() {
boolean overflowsContainer = false;
int width = (int) (mNodeRegion.mRight - mNodeRegion.mLeft);
int height = (int) (mNodeRegion.mBottom - mNodeRegion.mTop);
int width = (int) (mNodeRegion.getRight() - mNodeRegion.getLeft());
int height = (int) (mNodeRegion.getBottom() - mNodeRegion.getTop());
float leftBound = 0;
float rightBound = width;
@@ -349,23 +345,23 @@ import com.facebook.react.views.view.ReactClippingViewGroupHelper;
// to clip certain subviews.
if (!mClipToBounds && height > 0 && width > 0) {
for (NodeRegion region : mNodeRegions) {
if (region.mLeft < leftBound) {
leftBound = region.mLeft;
if (region.getLeft() < leftBound) {
leftBound = region.getLeft();
overflowsContainer = true;
}
if (region.mRight > rightBound) {
rightBound = region.mRight;
if (region.getRight() > rightBound) {
rightBound = region.getRight();
overflowsContainer = true;
}
if (region.mTop < topBound) {
topBound = region.mTop;
if (region.getTop() < topBound) {
topBound = region.getTop();
overflowsContainer = true;
}
if (region.mBottom > bottomBound) {
bottomBound = region.mBottom;
if (region.getBottom() > bottomBound) {
bottomBound = region.getBottom();
overflowsContainer = true;
}
}
@@ -424,8 +420,7 @@ import com.facebook.react.views.view.ReactClippingViewGroupHelper;
float right,
float bottom,
boolean isVirtual) {
if (mNodeRegion.mLeft != left || mNodeRegion.mTop != top || mNodeRegion.mRight != right ||
mNodeRegion.mBottom != bottom || mNodeRegion.mIsVirtual != isVirtual) {
if (!mNodeRegion.matches(left, top, right, bottom, isVirtual)) {
setNodeRegion(new NodeRegion(left, top, right, bottom, getReactTag(), isVirtual));
}
}

View File

@@ -356,12 +356,12 @@ import com.facebook.react.uimanager.UIViewOperationQueue;
}
int resultTag = region == NodeRegion.EMPTY ? touchTargetReactTag : region.mTag;
float x = PixelUtil.toDIPFromPixel(region.mLeft + MEASURE_BUFFER[0] - containerX);
float y = PixelUtil.toDIPFromPixel(region.mTop + MEASURE_BUFFER[1] - containerY);
float x = PixelUtil.toDIPFromPixel(region.getLeft() + MEASURE_BUFFER[0] - containerX);
float y = PixelUtil.toDIPFromPixel(region.getTop() + MEASURE_BUFFER[1] - containerY);
float width = PixelUtil.toDIPFromPixel(isNativeView ?
MEASURE_BUFFER[2] : region.mRight - region.mLeft);
MEASURE_BUFFER[2] : region.getRight() - region.getLeft());
float height = PixelUtil.toDIPFromPixel(isNativeView ?
MEASURE_BUFFER[3] : region.mBottom - region.mTop);
MEASURE_BUFFER[3] : region.getBottom() - region.getTop());
mCallback.invoke(resultTag, x, y, width, height);
}
}

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.flat;
import android.graphics.Rect;
/**
* NodeRegion that has a hit slop.
*/
/* package */ final class HitSlopNodeRegion extends NodeRegion {
private final Rect mHitSlop;
HitSlopNodeRegion(
Rect hitSlop,
float left,
float top,
float right,
float bottom,
int tag,
boolean isVirtual) {
super(left, top, right, bottom, tag, isVirtual);
mHitSlop = hitSlop;
}
@Override
/* package */ float getTouchableLeft() {
return getLeft() - mHitSlop.left;
}
@Override
/* package */ float getTouchableTop() {
return getTop() - mHitSlop.top;
}
@Override
/* package */ float getTouchableRight() {
return getRight() + mHitSlop.right;
}
@Override
/* package */ float getTouchableBottom() {
return getBottom() + mHitSlop.bottom;
}
@Override
/* package */ boolean withinBounds(float touchX, float touchY) {
return getTouchableLeft() <= touchX && touchX < getTouchableRight() &&
getTouchableTop() <= touchY && touchY < getTouchableBottom();
}
}

View File

@@ -70,11 +70,11 @@ import android.util.SparseIntArray;
public static void fillMaxMinArrays(NodeRegion[] regions, float[] maxRight, float[] minLeft) {
float last = 0;
for (int i = 0; i < regions.length; i++) {
last = Math.max(last, regions[i].mRight);
last = Math.max(last, regions[i].getTouchableRight());
maxRight[i] = last;
}
for (int i = regions.length - 1; i >= 0; i--) {
last = Math.min(last, regions[i].mLeft);
last = Math.min(last, regions[i].getTouchableLeft());
minLeft[i] = last;
}
}

View File

@@ -13,10 +13,10 @@ package com.facebook.react.flat;
/* package */ static final NodeRegion[] EMPTY_ARRAY = new NodeRegion[0];
/* 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;
private final float mLeft;
private final float mTop;
private final float mRight;
private final float mBottom;
/* package */ final int mTag;
/* package */ final boolean mIsVirtual;
@@ -41,12 +41,88 @@ package com.facebook.react.flat;
float right,
float bottom,
boolean isVirtual) {
return left == mLeft && top == mTop && bottom == mBottom && right == mRight &&
return left == mLeft && top == mTop && right == mRight && bottom == mBottom &&
isVirtual == mIsVirtual;
}
/* package */ final boolean withinBounds(float touchX, float touchY) {
return mLeft <= touchX && touchX < mRight && mTop <= touchY && touchY < mBottom;
/**
* The left bound of the underlying node.
*
* @return The node bound.
*/
/* package */ final float getLeft() {
return mLeft;
}
/**
* The top bound of the underlying node.
*
* @return The node bound.
*/
/* package */ final float getTop() {
return mTop;
}
/**
* The right bound of the underlying node.
*
* @return The node bound.
*/
/* package */ final float getRight() {
return mRight;
}
/**
* The bottom bound of the underlying node.
*
* @return The node bound.
*/
/* package */ final float getBottom() {
return mBottom;
}
/**
* The left bound of the region for the purpose of touch. This is usually the bound of the
* underlying node, except in the case of hit slop.
*
* @return The touch bound.
*/
/* package */ float getTouchableLeft() {
return getLeft();
}
/**
* The top bound of the region for the purpose of touch. This is usually the bound of the
* underlying node, except in the case of hit slop.
*
* @return The touch bound.
*/
/* package */ float getTouchableTop() {
return getTop();
}
/**
* The right bound of the region for the purpose of touch. This is usually the bound of the
* underlying node, except in the case of hit slop.
*
* @return The touch bound.
*/
/* package */ float getTouchableRight() {
return getRight();
}
/**
* The bottom bound of the region for the purpose of touch. This is usually the bound of the
* underlying node, except in the case of hit slop.
*
* @return The touch bound.
*/
/* package */ float getTouchableBottom() {
return getBottom();
}
/* package */ boolean withinBounds(float touchX, float touchY) {
return mLeft <= touchX && touchX < mRight && mTop <= touchY && touchY < mBottom;
}
/* package */ int getReactTag(float touchX, float touchY) {

View File

@@ -225,8 +225,7 @@ import com.facebook.textcachewarmer.DefaultTextLayoutCacheWarmer;
NodeRegion nodeRegion = getNodeRegion();
if (mDrawCommand == null) {
if (nodeRegion.mLeft != left || nodeRegion.mTop != top || nodeRegion.mRight != right ||
nodeRegion.mBottom != bottom || nodeRegion.mIsVirtual != isVirtual) {
if (!nodeRegion.matches(left, top, right, bottom, isVirtual)) {
setNodeRegion(new TextNodeRegion(left, top, right, bottom, getReactTag(), isVirtual, null));
}
return;
@@ -239,9 +238,7 @@ import com.facebook.textcachewarmer.DefaultTextLayoutCacheWarmer;
}
Layout newLayout = mDrawCommand.getLayout();
if (nodeRegion.mLeft != left || nodeRegion.mTop != top ||
nodeRegion.mRight != right || nodeRegion.mBottom != bottom ||
nodeRegion.mIsVirtual != isVirtual || layout != newLayout) {
if (!nodeRegion.matches(left, top, right, bottom, isVirtual) || layout != newLayout) {
setNodeRegion(
new TextNodeRegion(left, top, right, bottom, getReactTag(), isVirtual, newLayout));
}

View File

@@ -155,15 +155,10 @@ import com.facebook.react.uimanager.annotations.ReactPropGroup;
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));
setNodeRegion(mHitSlop == null ?
new NodeRegion(left, top, right, bottom, getReactTag(), isVirtual) :
new HitSlopNodeRegion(mHitSlop, left, top, right, bottom, getReactTag(), isVirtual));
}
}

View File

@@ -41,9 +41,9 @@ import android.text.Spanned;
if (mLayout != null) {
CharSequence text = mLayout.getText();
if (text instanceof Spanned) {
int y = Math.round(touchY - mTop);
int y = Math.round(touchY - getTop());
if (y >= mLayout.getLineTop(0) && y < mLayout.getLineBottom(mLayout.getLineCount() - 1)) {
float x = Math.round(touchX - mLeft);
float x = Math.round(touchX - getLeft());
int line = mLayout.getLineForVertical(y);
if (mLayout.getLineLeft(line) <= x && x <= mLayout.getLineRight(line)) {

View File

@@ -70,11 +70,11 @@ import android.util.SparseIntArray;
public static void fillMaxMinArrays(NodeRegion[] regions, float[] maxBottom, float[] minTop) {
float last = 0;
for (int i = 0; i < regions.length; i++) {
last = Math.max(last, regions[i].mBottom);
last = Math.max(last, regions[i].getTouchableBottom());
maxBottom[i] = last;
}
for (int i = regions.length - 1; i >= 0; i--) {
last = Math.min(last, regions[i].mTop);
last = Math.min(last, regions[i].getTouchableTop());
minTop[i] = last;
}
}