mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Refactor findTargetPathAndCoordinatesForTouch to improve perf of event delivery
Summary: Refactor of TouchTargetHelper.findTargetPathAndCoordinatesForTouch to avoid unnecessary lookup of views during the dispatching of Hover Events changelog: [internal] internal Reviewed By: lunaleaps, mdvacca Differential Revision: D32296003 fbshipit-source-id: 93834c37331ad5d75645a5665a1c8c3d965765fb
This commit is contained in:
1 parent
6563c99c49
commit
f40976cd24
2 files changed
+103
-42
No files matched your search
@@ -25,6 +25,7 @@ import com.facebook.react.uimanager.common.ViewUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Class responsible for identifying which react view should handle a given {@link MotionEvent}. It
|
||||
@@ -109,11 +110,12 @@ public class TouchTargetHelper {
|
||||
* @param eventY the Y screen coordinate of the touch location
|
||||
* @param viewGroup the container view to traverse
|
||||
* @param viewCoords an out parameter that will return the X,Y value in the target view
|
||||
* @return If a target was found, returns a path through the view tree of all react tags that are
|
||||
* a container for the touch target, ordered from target to root (last element)
|
||||
* @return If a target was found, returns a {@link Lis<ViewTarget>} containing the path through
|
||||
* the view tree of all react tags and views that are a container for the touch target,
|
||||
* ordered from target to root (last element)
|
||||
*/
|
||||
@SuppressLint("ResourceType")
|
||||
public static List<Integer> findTargetPathAndCoordinatesForTouch(
|
||||
public static List<ViewTarget> findTargetPathAndCoordinatesForTouch(
|
||||
float eventX, float eventY, ViewGroup viewGroup, float[] viewCoords) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
|
||||
@@ -121,7 +123,7 @@ public class TouchTargetHelper {
|
||||
viewCoords[0] = eventX;
|
||||
viewCoords[1] = eventY;
|
||||
|
||||
List<Integer> pathAccumulator = new ArrayList<>();
|
||||
List<ViewTarget> pathAccumulator = new ArrayList<>();
|
||||
View targetView = findTouchTargetViewWithPointerEvents(viewCoords, viewGroup, pathAccumulator);
|
||||
|
||||
if (targetView != null) {
|
||||
@@ -140,7 +142,7 @@ public class TouchTargetHelper {
|
||||
|
||||
int targetTag = getTouchTargetForView(reactTargetView, eventX, eventY);
|
||||
if (targetTag != reactTargetView.getId()) {
|
||||
pathAccumulator.add(0, targetTag);
|
||||
pathAccumulator.add(0, new ViewTarget(targetTag, (View) null));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +180,7 @@ public class TouchTargetHelper {
|
||||
float[] eventCoords,
|
||||
View view,
|
||||
EnumSet<TouchTargetReturnType> allowReturnTouchTargetTypes,
|
||||
List<Integer> pathAccumulator) {
|
||||
List<ViewTarget> pathAccumulator) {
|
||||
// We prefer returning a child, so we check for a child that can handle the touch first
|
||||
if (allowReturnTouchTargetTypes.contains(TouchTargetReturnType.CHILD)
|
||||
&& view instanceof ViewGroup) {
|
||||
@@ -303,7 +305,7 @@ public class TouchTargetHelper {
|
||||
* its descendants are the touch target.
|
||||
*/
|
||||
private static @Nullable View findTouchTargetViewWithPointerEvents(
|
||||
float eventCoords[], View view, @Nullable List<Integer> pathAccumulator) {
|
||||
float eventCoords[], View view, @Nullable List<ViewTarget> pathAccumulator) {
|
||||
PointerEvents pointerEvents =
|
||||
view instanceof ReactPointerEventsView
|
||||
? ((ReactPointerEventsView) view).getPointerEvents()
|
||||
@@ -330,7 +332,7 @@ public class TouchTargetHelper {
|
||||
findTouchTargetView(
|
||||
eventCoords, view, EnumSet.of(TouchTargetReturnType.SELF), pathAccumulator);
|
||||
if (targetView != null && pathAccumulator != null) {
|
||||
pathAccumulator.add(view.getId());
|
||||
pathAccumulator.add(new ViewTarget(view.getId(), view));
|
||||
}
|
||||
return targetView;
|
||||
|
||||
@@ -341,7 +343,7 @@ public class TouchTargetHelper {
|
||||
eventCoords, view, EnumSet.of(TouchTargetReturnType.CHILD), pathAccumulator);
|
||||
if (targetView != null) {
|
||||
if (pathAccumulator != null) {
|
||||
pathAccumulator.add(view.getId());
|
||||
pathAccumulator.add(new ViewTarget(view.getId(), view));
|
||||
}
|
||||
return targetView;
|
||||
}
|
||||
@@ -358,7 +360,7 @@ public class TouchTargetHelper {
|
||||
// make sure we exclude the View itself because of the PointerEvents.BOX_NONE
|
||||
if (reactTag != view.getId()) {
|
||||
if (pathAccumulator != null) {
|
||||
pathAccumulator.add(view.getId());
|
||||
pathAccumulator.add(new ViewTarget(view.getId(), view));
|
||||
}
|
||||
return view;
|
||||
}
|
||||
@@ -372,7 +374,7 @@ public class TouchTargetHelper {
|
||||
&& isTouchPointInView(eventCoords[0], eventCoords[1], view)
|
||||
&& ((ReactCompoundViewGroup) view).interceptsTouchEvent(eventCoords[0], eventCoords[1])) {
|
||||
if (pathAccumulator != null) {
|
||||
pathAccumulator.add(view.getId());
|
||||
pathAccumulator.add(new ViewTarget(view.getId(), view));
|
||||
}
|
||||
return view;
|
||||
}
|
||||
@@ -384,7 +386,7 @@ public class TouchTargetHelper {
|
||||
EnumSet.of(TouchTargetReturnType.SELF, TouchTargetReturnType.CHILD),
|
||||
pathAccumulator);
|
||||
if (result != null && pathAccumulator != null) {
|
||||
pathAccumulator.add(view.getId());
|
||||
pathAccumulator.add(new ViewTarget(view.getId(), view));
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -402,4 +404,47 @@ public class TouchTargetHelper {
|
||||
}
|
||||
return targetView.getId();
|
||||
}
|
||||
|
||||
public static class ViewTarget {
|
||||
private final int mViewId;
|
||||
private final @Nullable View mView;
|
||||
|
||||
private ViewTarget(int viewId, @Nullable View view) {
|
||||
mViewId = viewId;
|
||||
mView = view;
|
||||
}
|
||||
|
||||
public int getViewId() {
|
||||
return mViewId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public View getView() {
|
||||
return mView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
// If the object is compared with itself then return true
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if o is an instance of ViewTarget. Note that "null instanceof ViewTarget" also
|
||||
// returns false.
|
||||
if (!(o instanceof ViewTarget)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ViewTarget other = (ViewTarget) o;
|
||||
// We only need to compare view id, as we assume the same view id will always map to the same
|
||||
// view. TargetView is not mutable so this should be safe.
|
||||
return other.getViewId() == mViewId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(mViewId);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user