Skip to content

Commit 140f7be

Browse files
fix: Android hitSlop prop TalkBack selection
1 parent 6237882 commit 140f7be

1 file changed

Lines changed: 56 additions & 0 deletions

File tree

  • packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,62 @@ public open class ReactViewGroup public constructor(context: Context?) :
305305
return false
306306
}
307307

308+
// For accessibility (TalkBack), check if hover is within any child's hitSlop area
309+
if (ev.isFromSource(android.view.InputDevice.SOURCE_CLASS_POINTER) &&
310+
(ev.action == MotionEvent.ACTION_HOVER_ENTER || ev.action == MotionEvent.ACTION_HOVER_MOVE)) {
311+
val x = ev.x
312+
val y = ev.y
313+
314+
// Check each child in reverse order (front-to-back, matching touch behavior)
315+
for (i in childCount - 1 downTo 0) {
316+
val child = getChildAt(i)
317+
if (child == null || child.visibility != VISIBLE) {
318+
continue
319+
}
320+
321+
// Check if child has hitSlop
322+
if (child is ReactHitSlopView) {
323+
val hitSlopRect = child.hitSlopRect
324+
if (hitSlopRect != null) {
325+
// Calculate child-relative coordinates
326+
val childX = x - child.left
327+
val childY = y - child.top
328+
329+
// Check if within hitSlop-extended bounds
330+
if (childX >= -hitSlopRect.left &&
331+
childX < child.width + hitSlopRect.right &&
332+
childY >= -hitSlopRect.top &&
333+
childY < child.height + hitSlopRect.bottom) {
334+
335+
// Only intercept if OUTSIDE normal bounds but WITHIN hitSlop
336+
// This prevents interfering with normal child event handling
337+
val inNormalBounds = childX >= 0 && childX < child.width &&
338+
childY >= 0 && childY < child.height
339+
340+
if (!inNormalBounds) {
341+
// For TalkBack accessibility, request focus on the child
342+
if (ev.action == MotionEvent.ACTION_HOVER_ENTER) {
343+
child.performAccessibilityAction(
344+
android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS,
345+
null
346+
)
347+
return true
348+
}
349+
// Transform event coordinates to child's coordinate system
350+
ev.offsetLocation(-child.left.toFloat(), -child.top.toFloat())
351+
val handled = child.dispatchGenericMotionEvent(ev)
352+
// Restore original coordinates
353+
ev.offsetLocation(child.left.toFloat(), child.top.toFloat())
354+
if (handled) {
355+
return true
356+
}
357+
}
358+
}
359+
}
360+
}
361+
}
362+
}
363+
308364
return super.dispatchGenericMotionEvent(ev)
309365
}
310366

0 commit comments

Comments
 (0)