Skip to content

feat(Android, FormSheet v5): Setup TouchHandler on Dialog window#4204

Open
t0maboro wants to merge 1 commit into
@t0maboro/android-formsheet-v5from
@t0maboro/formsheet-android-touch-handler
Open

feat(Android, FormSheet v5): Setup TouchHandler on Dialog window#4204
t0maboro wants to merge 1 commit into
@t0maboro/android-formsheet-v5from
@t0maboro/formsheet-android-touch-handler

Conversation

@t0maboro

@t0maboro t0maboro commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Description

This PR implements the touch and pointer event handling for the FormSheet by making the ContentView to act as a separate React RootView.

When rendering React Native components inside a native Dialog, the views are rendered in a completely separate window. This breaks touch event dispatching because React Native's main ReactRootView is completely unaware of this detached window.

To solve this, we make FormSheetContentView implement the RootView interface and instantiate its own JSTouchDispatcher and JSPointerDispatcher. By overriding the standard Android touch and hover methods and feeding the MotionEvents directly into these local dispatchers, we successfully forward user interactions from the dialog's window into the RN event system.

Because FormSheetContentView establishes itself as a new, independent RootView boundary, the MotionEvent coordinates supplied by the Android framework are naturally scoped to the bounds of the dialog's window, resulting in the proper coordinate mapping for the React children without any shadow tree contentOriginOffset corrections.

Closes: https://github.com/software-mansion/react-native-screens-labs/issues/1548

Changes

  • FormSheetContentView now acts as a RootView.
  • Copied JSTouchDispatcher from RN core modal implementation to handle standard MotionEvents
  • Copied JSPointerDispatcher from RN core modal implementation to handle pointer events and hover states

Before & after - visual documentation

formsheet-pressables-android.mov

Test plan

Base test for formsheets, verify that pressables are working properly.

Checklist

  • Included code example that can be used to test this change.
  • For visual changes, included screenshots / GIFs / recordings documenting the change.
  • For API changes, updated relevant public types.
  • Ensured that CI passes

@t0maboro t0maboro marked this pull request as ready for review June 23, 2026 15:05
@t0maboro t0maboro changed the base branch from main to @t0maboro/android-formsheet-v5 June 23, 2026 15:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes touch/pointer event dispatch for the Android FormSheet (rendered inside a native Dialog) by turning the dialog’s content container into its own React RootView, with local JSTouchDispatcher / JSPointerDispatcher instances to route MotionEvents into React Native correctly.

Changes:

  • Make FormSheetContentView implement RootView and forward touch/hover/gesture events to JSTouchDispatcher and JSPointerDispatcher.
  • Make FormSheetHost implement ReactPointerEventsView with pointerEvents = NONE so the “empty” host in the main window doesn’t block hit-testing behind it.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
android/src/main/java/com/swmansion/rnscreens/gamma/modals/formsheet/FormSheetHost.kt Marks the host view as non-hit-testable in the main window via pointerEvents = NONE.
android/src/main/java/com/swmansion/rnscreens/gamma/modals/formsheet/FormSheetContentView.kt Adds RootView-style touch/pointer dispatching so dialog-window interactions reach the RN event system.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +107 to +117
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent): Boolean {
eventDispatcher?.let { eventDispatcher ->
jsTouchDispatcher.handleTouchEvent(event, eventDispatcher, themedReactContext)
jsPointerDispatcher?.handleMotionEvent(event, eventDispatcher, false)
}
super.onTouchEvent(event)
// In case when there is no children interested in handling touch event, we return true from
// the root view in order to receive subsequent events related to that gesture
return true
}
Comment on lines +152 to +154
override fun handleException(t: Throwable) {
themedReactContext.reactApplicationContext.handleException(RuntimeException(t))
}

@kmichalikk kmichalikk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runtime seems ok from quick glance, no further comments from me, but please look at what copilot added

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.

3 participants