mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Dispatch enter/leave for ancestor hit path
Summary: Changelog: [Internal] - Fix pointer event dispatch to also fire enter/leave for ancestors in the hit path. Compared the event order with web on the RNTester W3C pointer example Reviewed By: appden Differential Revision: D35403076 fbshipit-source-id: 726e45e49a901b1d97ad3e20f5898701fd1f763b
This commit is contained in:
committed by
Facebook GitHub Bot
parent
9bac0b77d0
commit
de09bd3b84
@@ -40,7 +40,7 @@ public class JSPointerDispatcher {
|
||||
|
||||
// Set globally for hover interactions, referenced for coalescing hover events
|
||||
private long mHoverInteractionKey = TouchEvent.UNSET;
|
||||
private List<Integer> mLastHitState = Collections.emptyList();
|
||||
private List<Integer> mLastHitPath = Collections.emptyList();
|
||||
private final float[] mLastEventCoordinates = new float[2];
|
||||
|
||||
public JSPointerDispatcher(ViewGroup viewGroup) {
|
||||
@@ -56,8 +56,10 @@ public class JSPointerDispatcher {
|
||||
return;
|
||||
}
|
||||
|
||||
int targetTag = findTargetTagAndSetCoordinates(motionEvent);
|
||||
dispatchCancelEvent(targetTag, motionEvent, eventDispatcher);
|
||||
List<Integer> hitPath =
|
||||
TouchTargetHelper.findTargetPathAndCoordinatesForTouch(
|
||||
motionEvent.getX(), motionEvent.getY(), mRootViewGroup, mTargetCoordinates);
|
||||
dispatchCancelEvent(hitPath, motionEvent, eventDispatcher);
|
||||
mChildHandlingNativeGesture = childView.getId();
|
||||
}
|
||||
|
||||
@@ -78,11 +80,15 @@ public class JSPointerDispatcher {
|
||||
|
||||
int surfaceId = UIManagerHelper.getSurfaceId(mRootViewGroup);
|
||||
int action = motionEvent.getActionMasked();
|
||||
int targetTag = findTargetTagAndSetCoordinates(motionEvent);
|
||||
List<Integer> hitPath =
|
||||
TouchTargetHelper.findTargetPathAndCoordinatesForTouch(
|
||||
motionEvent.getX(), motionEvent.getY(), mRootViewGroup, mTargetCoordinates);
|
||||
|
||||
int targetTag = hitPath.get(0);
|
||||
|
||||
if (supportsHover) {
|
||||
if (action == MotionEvent.ACTION_HOVER_MOVE) {
|
||||
handleHoverEvent(motionEvent, eventDispatcher, surfaceId);
|
||||
handleHoverEvent(motionEvent, eventDispatcher, surfaceId, hitPath);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -100,9 +106,12 @@ public class JSPointerDispatcher {
|
||||
mTouchEventCoalescingKeyHelper.addCoalescingKey(mDownStartTime);
|
||||
|
||||
if (!supportsHover) {
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(
|
||||
PointerEventHelper.POINTER_ENTER, surfaceId, targetTag, motionEvent));
|
||||
// Enter root -> child
|
||||
for (int i = hitPath.size(); i-- > 0; ) {
|
||||
int tag = hitPath.get(i);
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(PointerEventHelper.POINTER_ENTER, surfaceId, tag, motionEvent));
|
||||
}
|
||||
}
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(PointerEventHelper.POINTER_DOWN, surfaceId, targetTag, motionEvent));
|
||||
@@ -113,12 +122,6 @@ public class JSPointerDispatcher {
|
||||
// New pointer goes down, this can only happen after ACTION_DOWN is sent for the first pointer
|
||||
if (action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mDownStartTime);
|
||||
|
||||
if (!supportsHover) {
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(
|
||||
PointerEventHelper.POINTER_ENTER, surfaceId, targetTag, motionEvent));
|
||||
}
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(PointerEventHelper.POINTER_DOWN, surfaceId, targetTag, motionEvent));
|
||||
|
||||
@@ -153,16 +156,18 @@ public class JSPointerDispatcher {
|
||||
PointerEvent.obtain(PointerEventHelper.POINTER_UP, surfaceId, targetTag, motionEvent));
|
||||
|
||||
if (!supportsHover) {
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(
|
||||
PointerEventHelper.POINTER_LEAVE, surfaceId, targetTag, motionEvent));
|
||||
// Leave child -> root
|
||||
for (int i = 0; i < hitPath.size(); i++) {
|
||||
int tag = hitPath.get(i);
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(PointerEventHelper.POINTER_LEAVE, surfaceId, tag, motionEvent));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (action == MotionEvent.ACTION_CANCEL) {
|
||||
dispatchCancelEvent(targetTag, motionEvent, eventDispatcher);
|
||||
|
||||
dispatchCancelEvent(hitPath, motionEvent, eventDispatcher);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -184,7 +189,10 @@ public class JSPointerDispatcher {
|
||||
|
||||
// called on hover_move motion events only
|
||||
private void handleHoverEvent(
|
||||
MotionEvent motionEvent, EventDispatcher eventDispatcher, int surfaceId) {
|
||||
MotionEvent motionEvent,
|
||||
EventDispatcher eventDispatcher,
|
||||
int surfaceId,
|
||||
List<Integer> hitPath) {
|
||||
|
||||
int action = motionEvent.getActionMasked();
|
||||
if (action != MotionEvent.ACTION_HOVER_MOVE) {
|
||||
@@ -209,19 +217,15 @@ public class JSPointerDispatcher {
|
||||
mTouchEventCoalescingKeyHelper.addCoalescingKey(mHoverInteractionKey);
|
||||
}
|
||||
|
||||
List<Integer> currHitState =
|
||||
TouchTargetHelper.findTargetPathAndCoordinatesForTouch(
|
||||
x, y, mRootViewGroup, mTargetCoordinates);
|
||||
|
||||
// If child is handling, eliminate target tags under handling child
|
||||
if (mChildHandlingNativeGesture > 0) {
|
||||
int index = currHitState.indexOf(mChildHandlingNativeGesture);
|
||||
int index = hitPath.indexOf(mChildHandlingNativeGesture);
|
||||
if (index > 0) {
|
||||
currHitState.subList(0, index).clear();
|
||||
hitPath.subList(0, index).clear();
|
||||
}
|
||||
}
|
||||
|
||||
int targetTag = currHitState.size() > 0 ? currHitState.get(0) : -1;
|
||||
int targetTag = hitPath.size() > 0 ? hitPath.get(0) : -1;
|
||||
// If targetTag is empty, we should bail?
|
||||
if (targetTag == -1) {
|
||||
return;
|
||||
@@ -231,24 +235,25 @@ public class JSPointerDispatcher {
|
||||
// Traverse hitState back-to-front to find the first divergence with mLastHitState
|
||||
// FIXME: this may generate incorrect events when view collapsing changes the hierarchy
|
||||
int firstDivergentIndex = 0;
|
||||
while (firstDivergentIndex < Math.min(currHitState.size(), mLastHitState.size())
|
||||
&& currHitState
|
||||
.get(currHitState.size() - 1 - firstDivergentIndex)
|
||||
.equals(mLastHitState.get(mLastHitState.size() - 1 - firstDivergentIndex))) {
|
||||
while (firstDivergentIndex < Math.min(hitPath.size(), mLastHitPath.size())
|
||||
&& hitPath
|
||||
.get(hitPath.size() - 1 - firstDivergentIndex)
|
||||
.equals(mLastHitPath.get(mLastHitPath.size() - 1 - firstDivergentIndex))) {
|
||||
firstDivergentIndex++;
|
||||
}
|
||||
|
||||
boolean hasDiverged = firstDivergentIndex < Math.max(currHitState.size(), mLastHitState.size());
|
||||
boolean hasDiverged = firstDivergentIndex < Math.max(hitPath.size(), mLastHitPath.size());
|
||||
|
||||
// Fire all relevant enter events
|
||||
if (hasDiverged) {
|
||||
// If something has changed in either enter/exit, let's start a new coalescing key
|
||||
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mHoverInteractionKey);
|
||||
|
||||
List<Integer> enterTargetTags =
|
||||
currHitState.subList(0, currHitState.size() - firstDivergentIndex);
|
||||
List<Integer> enterTargetTags = hitPath.subList(0, hitPath.size() - firstDivergentIndex);
|
||||
if (enterTargetTags.size() > 0) {
|
||||
for (Integer enterTargetTag : enterTargetTags) {
|
||||
// root -> child
|
||||
for (int i = enterTargetTags.size(); i-- > 0; ) {
|
||||
int enterTargetTag = enterTargetTags.get(i);
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(
|
||||
PointerEventHelper.POINTER_ENTER, surfaceId, enterTargetTag, motionEvent));
|
||||
@@ -257,8 +262,9 @@ public class JSPointerDispatcher {
|
||||
|
||||
// Fire all relevant exit events
|
||||
List<Integer> exitTargetTags =
|
||||
mLastHitState.subList(0, mLastHitState.size() - firstDivergentIndex);
|
||||
mLastHitPath.subList(0, mLastHitPath.size() - firstDivergentIndex);
|
||||
if (exitTargetTags.size() > 0) {
|
||||
// child -> root
|
||||
for (Integer exitTargetTag : exitTargetTags) {
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(
|
||||
@@ -272,13 +278,13 @@ public class JSPointerDispatcher {
|
||||
PointerEvent.obtain(
|
||||
PointerEventHelper.POINTER_MOVE, surfaceId, targetTag, motionEvent, coalescingKey));
|
||||
|
||||
mLastHitState = currHitState;
|
||||
mLastHitPath = hitPath;
|
||||
mLastEventCoordinates[0] = x;
|
||||
mLastEventCoordinates[1] = y;
|
||||
}
|
||||
|
||||
private void dispatchCancelEvent(
|
||||
int targetTag, MotionEvent motionEvent, EventDispatcher eventDispatcher) {
|
||||
List<Integer> hitPath, MotionEvent motionEvent, EventDispatcher eventDispatcher) {
|
||||
// This means the gesture has already ended, via some other CANCEL or UP event. This is not
|
||||
// expected to happen very often as it would mean some child View has decided to intercept the
|
||||
// touch stream and start a native gesture only upon receiving the UP/CANCEL event.
|
||||
@@ -288,13 +294,17 @@ public class JSPointerDispatcher {
|
||||
"Expected to not have already sent a cancel for this gesture");
|
||||
int surfaceId = UIManagerHelper.getSurfaceId(mRootViewGroup);
|
||||
|
||||
int targetTag = hitPath.get(0);
|
||||
// Question: Does cancel fire on all in hit path?
|
||||
Assertions.assertNotNull(eventDispatcher)
|
||||
.dispatchEvent(
|
||||
PointerEvent.obtain(
|
||||
PointerEventHelper.POINTER_CANCEL, surfaceId, targetTag, motionEvent));
|
||||
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(PointerEventHelper.POINTER_LEAVE, surfaceId, targetTag, motionEvent));
|
||||
for (int tag : hitPath) {
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(PointerEventHelper.POINTER_LEAVE, surfaceId, tag, motionEvent));
|
||||
}
|
||||
|
||||
mTouchEventCoalescingKeyHelper.removeCoalescingKey(mDownStartTime);
|
||||
mDownStartTime = TouchEvent.UNSET;
|
||||
|
||||
Reference in New Issue
Block a user