mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add support for pointerover and pointerout
Summary: Changelog: [Internal] - Add pointerover, pointerout events Reviewed By: vincentriemer Differential Revision: D38559454 fbshipit-source-id: 829b9f2f22e1e41a64dcce80fcc79ab9e6352dcf
This commit is contained in:
committed by
Facebook GitHub Bot
parent
92e4ed6a28
commit
dfcd9faaad
@@ -58,6 +58,10 @@ constexpr MapBuffer::Key VP_ZINDEX = 34;
|
||||
constexpr MapBuffer::Key VP_POINTER_ENTER_CAPTURE = 38;
|
||||
constexpr MapBuffer::Key VP_POINTER_LEAVE_CAPTURE = 39;
|
||||
constexpr MapBuffer::Key VP_POINTER_MOVE_CAPTURE = 40;
|
||||
constexpr MapBuffer::Key VP_POINTER_OVER = 41;
|
||||
constexpr MapBuffer::Key VP_POINTER_OVER_CAPTURE = 42;
|
||||
constexpr MapBuffer::Key VP_POINTER_OUT = 43;
|
||||
constexpr MapBuffer::Key VP_POINTER_OUT_CAPTURE = 44;
|
||||
|
||||
// Yoga values
|
||||
constexpr MapBuffer::Key YG_BORDER_WIDTH = 100;
|
||||
@@ -475,6 +479,17 @@ static inline MapBuffer viewPropsDiff(
|
||||
builder.putBool(
|
||||
VP_POINTER_MOVE_CAPTURE,
|
||||
newProps.events[ViewEvents::Offset::PointerMoveCapture]);
|
||||
builder.putBool(
|
||||
VP_POINTER_OVER, newProps.events[ViewEvents::Offset::PointerOver]);
|
||||
builder.putBool(
|
||||
VP_POINTER_OVER_CAPTURE,
|
||||
newProps.events[ViewEvents::Offset::PointerOverCapture]);
|
||||
|
||||
builder.putBool(
|
||||
VP_POINTER_OUT, newProps.events[ViewEvents::Offset::PointerOut]);
|
||||
builder.putBool(
|
||||
VP_POINTER_OUT_CAPTURE,
|
||||
newProps.events[ViewEvents::Offset::PointerOutCapture]);
|
||||
}
|
||||
|
||||
if (oldProps.removeClippedSubviews != newProps.removeClippedSubviews) {
|
||||
|
||||
@@ -584,6 +584,16 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
MapBuilder.of(
|
||||
"phasedRegistrationNames",
|
||||
MapBuilder.of("bubbled", "onPointerUp", "captured", "onPointerUpCapture")))
|
||||
.put(
|
||||
"topPointerOut",
|
||||
MapBuilder.of(
|
||||
"phasedRegistrationNames",
|
||||
MapBuilder.of("bubbled", "onPointerOut", "captured", "onPointerOutCapture")))
|
||||
.put(
|
||||
"topPointerOver",
|
||||
MapBuilder.of(
|
||||
"phasedRegistrationNames",
|
||||
MapBuilder.of("bubbled", "onPointerOver", "captured", "onPointerOverCapture")))
|
||||
.build());
|
||||
return eventTypeConstants;
|
||||
}
|
||||
@@ -643,6 +653,26 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||
view.setTag(R.id.pointer_enter_capture, value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "onPointerOver")
|
||||
public void setPointerOver(@NonNull T view, boolean value) {
|
||||
view.setTag(R.id.pointer_over, value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "onPointerOverCapture")
|
||||
public void setPointerOverCapture(@NonNull T view, boolean value) {
|
||||
view.setTag(R.id.pointer_over_capture, value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "onPointerOut")
|
||||
public void setPointerOut(@NonNull T view, boolean value) {
|
||||
view.setTag(R.id.pointer_out, value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "onPointerOutCapture")
|
||||
public void setPointerOutCapture(@NonNull T view, boolean value) {
|
||||
view.setTag(R.id.pointer_out_capture, value);
|
||||
}
|
||||
|
||||
@ReactProp(name = "onPointerLeave")
|
||||
public void setPointerLeave(@NonNull T view, boolean value) {
|
||||
view.setTag(R.id.pointer_leave, value);
|
||||
|
||||
@@ -119,6 +119,20 @@ public class JSPointerDispatcher {
|
||||
mTouchEventCoalescingKeyHelper.addCoalescingKey(mDownStartTime);
|
||||
|
||||
if (!supportsHover) {
|
||||
// Indirect OVER event dispatches before ENTER
|
||||
boolean listeningForOver =
|
||||
isAnyoneListeningForBubblingEvent(hitPath, EVENT.OVER, EVENT.OVER_CAPTURE);
|
||||
if (listeningForOver) {
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(
|
||||
PointerEventHelper.POINTER_OVER,
|
||||
surfaceId,
|
||||
activeTargetTag,
|
||||
motionEvent,
|
||||
mTargetCoordinates,
|
||||
mPrimaryPointerId));
|
||||
}
|
||||
|
||||
List<ViewTarget> enterViewTargets =
|
||||
filterByShouldDispatch(hitPath, EVENT.ENTER, EVENT.ENTER_CAPTURE, false);
|
||||
|
||||
@@ -158,6 +172,8 @@ public class JSPointerDispatcher {
|
||||
if (action == MotionEvent.ACTION_POINTER_DOWN) {
|
||||
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mDownStartTime);
|
||||
|
||||
// TODO(luwe) We need to fire indirect over,enter events for secondary pointers
|
||||
|
||||
boolean listeningForDown =
|
||||
isAnyoneListeningForBubblingEvent(hitPath, EVENT.DOWN, EVENT.DOWN_CAPTURE);
|
||||
if (listeningForDown) {
|
||||
@@ -198,6 +214,8 @@ public class JSPointerDispatcher {
|
||||
if (action == MotionEvent.ACTION_POINTER_UP) {
|
||||
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mDownStartTime);
|
||||
|
||||
// TODO(luwe) We need to fire indirect out,leave events for secondary pointers
|
||||
|
||||
boolean listeningForUp =
|
||||
isAnyoneListeningForBubblingEvent(hitPath, EVENT.UP, EVENT.UP_CAPTURE);
|
||||
if (listeningForUp) {
|
||||
@@ -235,6 +253,19 @@ public class JSPointerDispatcher {
|
||||
}
|
||||
|
||||
if (!supportsHover) {
|
||||
boolean listeningForOut =
|
||||
isAnyoneListeningForBubblingEvent(hitPath, EVENT.OUT, EVENT.OUT_CAPTURE);
|
||||
if (listeningForOut) {
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(
|
||||
PointerEventHelper.POINTER_OUT,
|
||||
surfaceId,
|
||||
activeTargetTag,
|
||||
motionEvent,
|
||||
mTargetCoordinates,
|
||||
mPrimaryPointerId));
|
||||
}
|
||||
|
||||
List<ViewTarget> leaveViewTargets =
|
||||
filterByShouldDispatch(hitPath, EVENT.LEAVE, EVENT.LEAVE_CAPTURE, false);
|
||||
|
||||
@@ -408,6 +439,53 @@ public class JSPointerDispatcher {
|
||||
// If something has changed in either enter/exit, let's start a new coalescing key
|
||||
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mHoverInteractionKey);
|
||||
|
||||
// Out, Leave events
|
||||
if (mLastHitPath.size() > 0) {
|
||||
int lastTargetTag = mLastHitPath.get(0).getViewId();
|
||||
boolean listeningForOut =
|
||||
isAnyoneListeningForBubblingEvent(mLastHitPath, EVENT.OUT, EVENT.OUT_CAPTURE);
|
||||
if (listeningForOut) {
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(
|
||||
PointerEventHelper.POINTER_OUT,
|
||||
surfaceId,
|
||||
lastTargetTag,
|
||||
motionEvent,
|
||||
mTargetCoordinates,
|
||||
mPrimaryPointerId));
|
||||
}
|
||||
|
||||
// target -> root
|
||||
List<ViewTarget> leaveViewTargets =
|
||||
filterByShouldDispatch(
|
||||
mLastHitPath.subList(0, mLastHitPath.size() - firstDivergentIndexFromBack),
|
||||
EVENT.LEAVE,
|
||||
EVENT.LEAVE_CAPTURE,
|
||||
nonDivergentListeningToLeave);
|
||||
if (leaveViewTargets.size() > 0) {
|
||||
// We want to dispatch from target -> root, so no need to reverse
|
||||
dispatchEventForViewTargets(
|
||||
PointerEventHelper.POINTER_LEAVE,
|
||||
leaveViewTargets,
|
||||
eventDispatcher,
|
||||
surfaceId,
|
||||
motionEvent);
|
||||
}
|
||||
}
|
||||
|
||||
boolean listeningForOver =
|
||||
isAnyoneListeningForBubblingEvent(hitPath, EVENT.OVER, EVENT.OVER_CAPTURE);
|
||||
if (listeningForOver) {
|
||||
eventDispatcher.dispatchEvent(
|
||||
PointerEvent.obtain(
|
||||
PointerEventHelper.POINTER_OVER,
|
||||
surfaceId,
|
||||
targetTag,
|
||||
motionEvent,
|
||||
mTargetCoordinates,
|
||||
mPrimaryPointerId));
|
||||
}
|
||||
|
||||
// target -> root
|
||||
List<ViewTarget> enterViewTargets =
|
||||
filterByShouldDispatch(
|
||||
@@ -426,23 +504,6 @@ public class JSPointerDispatcher {
|
||||
surfaceId,
|
||||
motionEvent);
|
||||
}
|
||||
|
||||
// target -> root
|
||||
List<ViewTarget> leaveViewTargets =
|
||||
filterByShouldDispatch(
|
||||
mLastHitPath.subList(0, mLastHitPath.size() - firstDivergentIndexFromBack),
|
||||
EVENT.LEAVE,
|
||||
EVENT.LEAVE_CAPTURE,
|
||||
nonDivergentListeningToLeave);
|
||||
if (leaveViewTargets.size() > 0) {
|
||||
// We want to dispatch from target -> root, so no need to reverse
|
||||
dispatchEventForViewTargets(
|
||||
PointerEventHelper.POINTER_LEAVE,
|
||||
leaveViewTargets,
|
||||
eventDispatcher,
|
||||
surfaceId,
|
||||
motionEvent);
|
||||
}
|
||||
}
|
||||
|
||||
int coalescingKey = mTouchEventCoalescingKeyHelper.getCoalescingKey(mHoverInteractionKey);
|
||||
|
||||
@@ -218,6 +218,8 @@ public class PointerEvent extends Event<PointerEvent> {
|
||||
case PointerEventHelper.POINTER_DOWN:
|
||||
case PointerEventHelper.POINTER_UP:
|
||||
case PointerEventHelper.POINTER_LEAVE:
|
||||
case PointerEventHelper.POINTER_OUT:
|
||||
case PointerEventHelper.POINTER_OVER:
|
||||
pointersEventData = Arrays.asList(createPointerEventData(activePointerIndex));
|
||||
break;
|
||||
}
|
||||
|
||||
+24
@@ -36,6 +36,10 @@ public class PointerEventHelper {
|
||||
MOVE_CAPTURE,
|
||||
UP,
|
||||
UP_CAPTURE,
|
||||
OUT,
|
||||
OUT_CAPTURE,
|
||||
OVER,
|
||||
OVER_CAPTURE,
|
||||
};
|
||||
|
||||
public static final String POINTER_CANCEL = "topPointerCancel";
|
||||
@@ -44,6 +48,8 @@ public class PointerEventHelper {
|
||||
public static final String POINTER_LEAVE = "topPointerLeave";
|
||||
public static final String POINTER_MOVE = "topPointerMove";
|
||||
public static final String POINTER_UP = "topPointerUp";
|
||||
public static final String POINTER_OVER = "topPointerOver";
|
||||
public static final String POINTER_OUT = "topPointerOut";
|
||||
|
||||
/** We don't dispatch capture events from native; that's currently handled by JS. */
|
||||
public static @Nullable String getDispatchableEventName(EVENT event) {
|
||||
@@ -60,6 +66,10 @@ public class PointerEventHelper {
|
||||
return PointerEventHelper.POINTER_CANCEL;
|
||||
case UP:
|
||||
return PointerEventHelper.POINTER_UP;
|
||||
case OVER:
|
||||
return PointerEventHelper.POINTER_OVER;
|
||||
case OUT:
|
||||
return PointerEventHelper.POINTER_OUT;
|
||||
default:
|
||||
FLog.e(ReactConstants.TAG, "No dispatchable event name for type: " + event);
|
||||
return null;
|
||||
@@ -121,6 +131,18 @@ public class PointerEventHelper {
|
||||
case MOVE_CAPTURE:
|
||||
value = view.getTag(R.id.pointer_move_capture);
|
||||
break;
|
||||
case OVER:
|
||||
value = view.getTag(R.id.pointer_over);
|
||||
break;
|
||||
case OVER_CAPTURE:
|
||||
value = view.getTag(R.id.pointer_over_capture);
|
||||
break;
|
||||
case OUT:
|
||||
value = view.getTag(R.id.pointer_out);
|
||||
break;
|
||||
case OUT_CAPTURE:
|
||||
value = view.getTag(R.id.pointer_out_capture);
|
||||
break;
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
@@ -147,6 +169,8 @@ public class PointerEventHelper {
|
||||
case POINTER_MOVE:
|
||||
case POINTER_ENTER:
|
||||
case POINTER_LEAVE:
|
||||
case POINTER_OVER:
|
||||
case POINTER_OUT:
|
||||
return EventCategoryDef.CONTINUOUS;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,10 @@ object ReactMapBufferPropSetter {
|
||||
private const val VP_POINTER_ENTER_CAPTURE = 38
|
||||
private const val VP_POINTER_LEAVE_CAPTURE = 39
|
||||
private const val VP_POINTER_MOVE_CAPTURE = 40
|
||||
private const val VP_POINTER_OUT = 41
|
||||
private const val VP_POINTER_OUT_CAPTURE = 42
|
||||
private const val VP_POINTER_OVER = 43
|
||||
private const val VP_POINTER_OVER_CAPTURE = 44
|
||||
|
||||
// Yoga values
|
||||
private const val YG_BORDER_WIDTH = 100
|
||||
@@ -197,6 +201,18 @@ object ReactMapBufferPropSetter {
|
||||
VP_POINTER_MOVE_CAPTURE -> {
|
||||
viewManager.setPointerMoveCapture(view, entry.booleanValue)
|
||||
}
|
||||
VP_POINTER_OUT -> {
|
||||
viewManager.setPointerOut(view, entry.booleanValue)
|
||||
}
|
||||
VP_POINTER_OUT_CAPTURE -> {
|
||||
viewManager.setPointerOutCapture(view, entry.booleanValue)
|
||||
}
|
||||
VP_POINTER_OVER -> {
|
||||
viewManager.setPointerOver(view, entry.booleanValue)
|
||||
}
|
||||
VP_POINTER_OVER_CAPTURE -> {
|
||||
viewManager.setPointerOverCapture(view, entry.booleanValue)
|
||||
}
|
||||
VP_REMOVE_CLIPPED_SUBVIEW -> {
|
||||
viewManager.setRemoveClippedSubviews(view, entry.booleanValue)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user