Skip to content

fix(bottomsheet:android): forward touch-behind events with raw coordi…#484

Open
Siergiej29 wants to merge 1 commit into
nativescript-community:masterfrom
Siergiej29:fix/bottomsheet-can-touch-behind-coordinates
Open

fix(bottomsheet:android): forward touch-behind events with raw coordi…#484
Siergiej29 wants to merge 1 commit into
nativescript-community:masterfrom
Siergiej29:fix/bottomsheet-can-touch-behind-coordinates

Conversation

@Siergiej29
Copy link
Copy Markdown

Summary

This PR fixes Android touch forwarding when canTouchBehind is enabled in @nativescript-community/ui-material-bottomsheet.

When a bottom sheet is used as a transparent overlay above an interactive screen, touches passed through to the underlying Activity can be dispatched with incorrect coordinates. The visible UI remains in the correct position, but the actual touch targets behind the sheet can be shifted downward.

The fix creates a copied MotionEvent, updates it to use raw screen coordinates, dispatches that copied event to the Activity, and recycles it in a finally block.

Problem

I am using a bottom sheet as an overlay on top of an interactive map screen.

The intended behavior is:

  • no dimmed backdrop
  • content behind the sheet remains visible
  • content behind the sheet remains interactive
  • tapping controls behind the sheet does not close the sheet
  • touches behind the sheet hit the visible UI at the same screen position

The current configuration is:

{
  canTouchBehind: true,
  disableDimBackground: true,
  dismissOnBackgroundTap: false,
  transparent: true,
}

On Android, the UI behind the sheet is rendered in the correct place, but the touch target appears to be shifted downward. For example, map controls or test buttons are visible in one position, but they only react when tapping below them.

Root Cause

The current Android implementation forwards the original MotionEvent directly to the Activity:

fragment.getActivity().dispatchTouchEvent(event);

This is fragile because the event originates from the bottom sheet/dialog overlay window, while the Activity/root view may interpret the event in a different coordinate space.

That matches the observed behavior: the underlying UI is visually correct, but hit testing happens with shifted coordinates.

Fix

Instead of forwarding the original event directly, this PR copies the event, updates its coordinates to raw screen coordinates, dispatches the copied event, and recycles it safely:

  const forwardedEvent = android.view.MotionEvent.obtain(event);
  forwardedEvent.setLocation(event.getRawX(), event.getRawY());

  try {
      fragment.getActivity().dispatchTouchEvent(forwardedEvent);
  } finally {
      forwardedEvent.recycle();
  }

Using try/finally ensures the copied MotionEvent is recycled even if dispatching throws.

Reproduction

A minimal reproduction project is available here:

The reproduction includes:

  • a page with interactive buttons and controls behind the bottom sheet
  • a bottom sheet opened with canTouchBehind: true
  • disableDimBackground: true
  • dismissOnBackgroundTap: false
  • transparent: true

Steps:

  1. Open the reproduction app on Android.
  2. Navigate to the bottom sheet touch test page.
  3. Open the bottom sheet.
  4. Tap the visible buttons/controls behind the sheet.
  5. Observe that without this fix, the controls react only when tapping below their visible position.
  6. Apply this fix and repeat the same test.
  7. The controls behind the sheet should receive touches at the correct visible position.

Notes

The README currently mentions that canTouchBehind works properly when dismissOnBackgroundTap is set to true.

This issue specifically affects the use case where the sheet should stay open while interacting with the content behind it, so the configuration uses:

dismissOnBackgroundTap: false

Even if this combination is considered a special case, forwarding a copied event with screen coordinates is safer than dispatching the original overlay event directly.

Testing

Tested locally in a NativeScript app on Android with:

  {
    canTouchBehind: true,
    disableDimBackground: true,
    dismissOnBackgroundTap: false,
    transparent: true,
  }

The underlying controls receive touches at the expected visible position after applying this change.

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