Repository navigation
fix(android): skip hidden children when finding a touch target - #59524
bitsniper-ai wants to merge 1 commit into
Conversation
|
Hi @bitsniper-ai! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
c78ad09 to
4cdbf24
Compare
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
|
@javache has imported this pull request. If you are a Meta employee, you can view this in D127811837. |
Summary:
TouchTargetHelper.findTouchTargetViewwalks a view's children from the top down and returns the first one under the touch point, without checking whether that child is shown. A native child that isGONEorINVISIBLEtherefore becomes the touch target, and the touch is lost: nothing under it receives it.The common case is
RefreshControlon Android.SwipeRefreshLayoutkeeps its refresh indicator (aCircleImageView) as a child that restsGONEat the top centre of the scroll view. Every tap on content under that resting box, such as a button or chip near the top of a list, goes to the hidden indicator instead. This is #33163, which was closed as stale without a fix.Android's own dispatch has the rule this applies:
ViewGroup.canViewReceivePointerEventslets a child take a pointer event only when it isVISIBLEor has an animation running. This change skips any other child in the same loop, before the child's point is computed.The only React-managed views React Native hides are
display: 'none'ones (SurfaceMountingManager.updateLayoutsets themINVISIBLE), which should never take a touch either; Yoga lays them out at zero size, so today only ahitSlopcould reach one. Every other view that changes outcome is a hidden native child that Android's own dispatch would never send a touch to.Changelog:
[ANDROID] [FIXED] - Hidden native children (such as RefreshControl's resting indicator) no longer swallow touches meant for the views under them
Test Plan:
Repro: a
ScrollViewwith aRefreshControland aPressableat the top centre of its content.Pressablewhere it overlaps the indicator's resting box does nothing (onPressnever fires); tapping its other parts works.PressablefiresonPress; pull to refresh still shows the indicator and refreshes.Checked on: Samsung S21 (Android 15), React Native 0.86.3 (Fabric), built from source with this change. In our app, a filter chip at the top of a pull-to-refresh list: before, taps inside the indicator's resting box (
CircleImageView,GONE, at [650,305][790,445]) never reached the chip; after, 9 of 9 taps across that box selected it.🤖 Generated with Claude Code