Skip to content

fix: let views drawn over a scrollable drag the sheet - #88

Open
dkulakov wants to merge 1 commit into
software-mansion-labs:mainfrom
dkulakov:fix/scrollable-occlusion
Open

dkulakov wants to merge 1 commit into
software-mansion-labs:mainfrom
dkulakov:fix/scrollable-occlusion

Conversation

@dkulakov

Copy link
Copy Markdown

Problem

When a view is drawn over a ScrollView inside the sheet (for example an absolutely positioned header or grabber, so the list scrolls underneath it), dragging that view could not move the sheet while the list was scrolled away from its top. At the largest detent the sheet treated the touch as a list touch and refused to collapse, and the list never received the touch either, so nothing moved.

Root cause

Both platforms chose "the scrollable under the finger" by geometry alone: any vertically scrollable view whose bounds contained the touch, even when another view was drawn over it.

Fix

  • iOS: resolve the touched view with UIKit hit-testing (sheetContainer.hitTest), which honors pointerEvents, zIndex, and hidden or transparent views, then collect that view's scrollable ancestors. Content interaction is briefly re-enabled during the hit test, so grabbing the sheet mid-settle still resolves the content.
  • Android: the lookup now follows React Native's TouchTargetHelper rules. The topmost child that can take the touch wins, so a non-scrollable view shields what is underneath it. It respects pointerEvents, including on ReactScrollView and ReactHorizontalScrollView, which don't implement ReactPointerEventsView. Disabled views pass touches through, and child transforms and parent scroll offsets are taken into account.

Example

New "Draggable grabber" demo: a modal sheet with a full-height ScrollView and a transparent grabber strip on top of it.

Testing

Tested manually on the iOS simulator and an Android emulator:

  • With the list scrolled, dragging the grabber or a header closes the sheet.
  • Dragging the list itself still scrolls it.
  • Overlays with pointerEvents="none" or "box-none", and the unscaled area of a scaled overlay, still let the list scroll.

Note

On Android, a downward drag that starts within about 12–24 dp below the status bar can be cancelled by the system (FLAG_CANCELED, the notification-shade gesture). This is OS behavior and unrelated to this change.

iOS Android
iphone.simulator.mov
android.emulator.mov

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant