Skip to content

Commit 8de8d52

Browse files
authored
fix(android): touch events on android new arch (#156)
* fix(android): touch events on android new arch * docs: updated gestures troubleshooting docs * fix(android): enable disallow intercept touch event * refactor: style objects
1 parent bbb534b commit 8de8d52

File tree

10 files changed

+130
-116
lines changed

10 files changed

+130
-116
lines changed

android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,19 @@ import com.lodev09.truesheet.core.Utils
1919
class TrueSheetView(context: Context) :
2020
ViewGroup(context),
2121
LifecycleEventListener {
22-
private var eventDispatcher: EventDispatcher? = null
2322

2423
private val reactContext: ThemedReactContext
2524
get() = context as ThemedReactContext
2625

2726
private val surfaceId: Int
2827
get() = UIManagerHelper.getSurfaceId(this)
2928

29+
var eventDispatcher: EventDispatcher?
30+
get() = rootSheetView.eventDispatcher
31+
set(eventDispatcher) {
32+
rootSheetView.eventDispatcher = eventDispatcher
33+
}
34+
3035
var initialIndex: Int = -1
3136
var initialIndexAnimated: Boolean = true
3237

@@ -62,11 +67,8 @@ class TrueSheetView(context: Context) :
6267

6368
init {
6469
reactContext.addLifecycleEventListener(this)
65-
eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
6670

6771
rootSheetView = RootSheetView(context)
68-
rootSheetView.eventDispatcher = eventDispatcher
69-
7072
sheetDialog = TrueSheetDialog(reactContext, rootSheetView)
7173

7274
// Configure Sheet Dialog
@@ -173,6 +175,13 @@ class TrueSheetView(context: Context) :
173175
// Do nothing as we are laid out by UIManager
174176
}
175177

178+
override fun setId(id: Int) {
179+
super.setId(id)
180+
181+
// Forward the ID to our content view, so event dispatching behaves correctly
182+
rootSheetView.id = id
183+
}
184+
176185
override fun onAttachedToWindow() {
177186
super.onAttachedToWindow()
178187

@@ -193,7 +202,7 @@ class TrueSheetView(context: Context) :
193202

194203
override fun onDetachedFromWindow() {
195204
super.onDetachedFromWindow()
196-
sheetDialog.dismiss()
205+
onDropInstance()
197206
}
198207

199208
override fun addView(child: View, index: Int) {
@@ -219,7 +228,6 @@ class TrueSheetView(context: Context) :
219228

220229
override fun removeViewAt(index: Int) {
221230
UiThreadUtil.assertOnUiThread()
222-
223231
val child = getChildAt(index)
224232
rootSheetView.removeView(child)
225233
}
@@ -229,14 +237,12 @@ class TrueSheetView(context: Context) :
229237
// Those will be handled by the rootView which lives in the dialog
230238
}
231239

232-
override fun dispatchPopulateAccessibilityEvent(event: AccessibilityEvent): Boolean {
233-
// Explicitly override this to prevent accessibility events being passed down to children
234-
// Those will be handled by the rootView which lives in the dialog
235-
return false
236-
}
240+
// Explicitly override this to prevent accessibility events being passed down to children
241+
// Those will be handled by the mHostView which lives in the dialog
242+
public override fun dispatchPopulateAccessibilityEvent(event: AccessibilityEvent): Boolean = false
237243

238244
override fun onHostResume() {
239-
// do nothing
245+
configureIfShowing()
240246
}
241247

242248
override fun onHostPause() {
@@ -245,6 +251,10 @@ class TrueSheetView(context: Context) :
245251

246252
override fun onHostDestroy() {
247253
// Drop the instance if the host is destroyed which will dismiss the dialog
254+
onDropInstance()
255+
}
256+
257+
fun onDropInstance() {
248258
reactContext.removeLifecycleEventListener(this)
249259
sheetDialog.dismiss()
250260
}
@@ -311,7 +321,7 @@ class TrueSheetView(context: Context) :
311321
eventDispatcher?.dispatchEvent(TrueSheetEvent(surfaceId, id, name, data))
312322
}
313323

314-
private fun configureIfShowing() {
324+
fun configureIfShowing() {
315325
if (sheetDialog.isShowing) {
316326
sheetDialog.configure()
317327
sheetDialog.positionFooter()

android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.facebook.react.bridge.ReadableArray
88
import com.facebook.react.bridge.ReadableType
99
import com.facebook.react.common.MapBuilder
1010
import com.facebook.react.uimanager.ThemedReactContext
11+
import com.facebook.react.uimanager.UIManagerHelper
1112
import com.facebook.react.uimanager.ViewGroupManager
1213
import com.facebook.react.uimanager.annotations.ReactProp
1314
import com.lodev09.truesheet.core.Utils
@@ -19,7 +20,19 @@ class TrueSheetViewManager : ViewGroupManager<TrueSheetView>() {
1920

2021
override fun onDropViewInstance(view: TrueSheetView) {
2122
super.onDropViewInstance(view)
22-
view.onHostDestroy()
23+
view.onDropInstance()
24+
}
25+
26+
override fun addEventEmitters(reactContext: ThemedReactContext, view: TrueSheetView) {
27+
val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
28+
dispatcher?.let {
29+
view.eventDispatcher = it
30+
}
31+
}
32+
33+
override fun onAfterUpdateTransaction(view: TrueSheetView) {
34+
super.onAfterUpdateTransaction(view)
35+
view.configureIfShowing()
2336
}
2437

2538
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> =

android/src/main/java/com/lodev09/truesheet/core/RootSheetView.kt

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ class RootSheetView(private val context: Context?) :
3232

3333
private val jSTouchDispatcher = JSTouchDispatcher(this)
3434
private var jSPointerDispatcher: JSPointerDispatcher? = null
35-
var sizeChangeListener: ((w: Int, h: Int) -> Unit)? = null
3635

36+
var sizeChangeListener: ((w: Int, h: Int) -> Unit)? = null
3737
var eventDispatcher: EventDispatcher? = null
3838

3939
private val reactContext: ThemedReactContext
@@ -59,53 +59,44 @@ class RootSheetView(private val context: Context?) :
5959
}
6060

6161
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
62-
eventDispatcher?.let { jSTouchDispatcher.handleTouchEvent(event, it) }
63-
jSPointerDispatcher?.handleMotionEvent(event, eventDispatcher, true)
62+
eventDispatcher?.let { eventDispatcher ->
63+
jSTouchDispatcher.handleTouchEvent(event, eventDispatcher, reactContext)
64+
jSPointerDispatcher?.handleMotionEvent(event, eventDispatcher, true)
65+
}
6466
return super.onInterceptTouchEvent(event)
6567
}
6668

6769
@SuppressLint("ClickableViewAccessibility")
6870
override fun onTouchEvent(event: MotionEvent): Boolean {
69-
eventDispatcher?.let { jSTouchDispatcher.handleTouchEvent(event, it) }
70-
jSPointerDispatcher?.handleMotionEvent(event, eventDispatcher, false)
71+
eventDispatcher?.let { eventDispatcher ->
72+
jSTouchDispatcher.handleTouchEvent(event, eventDispatcher, reactContext)
73+
jSPointerDispatcher?.handleMotionEvent(event, eventDispatcher, false)
74+
}
7175
super.onTouchEvent(event)
72-
7376
// In case when there is no children interested in handling touch event, we return true from
7477
// the root view in order to receive subsequent events related to that gesture
7578
return true
7679
}
7780

7881
override fun onInterceptHoverEvent(event: MotionEvent): Boolean {
79-
jSPointerDispatcher?.handleMotionEvent(event, eventDispatcher, true)
82+
eventDispatcher?.let { jSPointerDispatcher?.handleMotionEvent(event, it, true) }
8083
return super.onHoverEvent(event)
8184
}
8285

8386
override fun onHoverEvent(event: MotionEvent): Boolean {
84-
jSPointerDispatcher?.handleMotionEvent(event, eventDispatcher, false)
87+
eventDispatcher?.let { jSPointerDispatcher?.handleMotionEvent(event, it, false) }
8588
return super.onHoverEvent(event)
8689
}
8790

88-
@Deprecated("Deprecated in Java")
89-
override fun onChildStartedNativeGesture(ev: MotionEvent) {
90-
eventDispatcher?.let {
91-
if (ev != null) {
92-
jSTouchDispatcher.onChildStartedNativeGesture(ev, it)
93-
}
91+
override fun onChildStartedNativeGesture(childView: View, ev: MotionEvent) {
92+
eventDispatcher?.let { eventDispatcher ->
93+
jSTouchDispatcher.onChildStartedNativeGesture(ev, eventDispatcher)
94+
jSPointerDispatcher?.onChildStartedNativeGesture(childView, ev, eventDispatcher)
9495
}
9596
}
9697

97-
override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
98-
eventDispatcher?.let { jSTouchDispatcher.onChildStartedNativeGesture(ev, it) }
99-
jSPointerDispatcher?.onChildStartedNativeGesture(childView, ev, eventDispatcher)
100-
}
101-
10298
override fun onChildEndedNativeGesture(childView: View, ev: MotionEvent) {
10399
eventDispatcher?.let { jSTouchDispatcher.onChildEndedNativeGesture(ev, it) }
104100
jSPointerDispatcher?.onChildEndedNativeGesture()
105101
}
106-
107-
override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
108-
// No-op - override in order to still receive events to onInterceptTouchEvent
109-
// even when some other view disallow that
110-
}
111102
}

docs/docs/troubleshooting.mdx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,20 @@ On Android, [RNGH does not work](https://docs.swmansion.com/react-native-gesture
1616
import { GestureHandlerRootView } from 'react-native-gesture-handler'
1717
```
1818

19-
```tsx
19+
```tsx {3-5}
2020
return (
2121
<TrueSheet ref={sheet}>
22-
<GestureHandlerRootView>
22+
<GestureHandlerRootView style={{ flexGrow: 1 }}>
2323
<View />
2424
</GestureHandlerRootView>
2525
</TrueSheet>
2626
)
2727
```
2828

29+
:::info
30+
Note that we are using `flexGrow` instead of `flex` here. For some weird reason, `flex` does not work correctly. See [below](#weird-layout-render).
31+
:::
32+
2933
## React Navigation
3034

3135
[`react-navigation`](https://reactnavigation.org)
@@ -35,7 +39,7 @@ return (
3539
On IOS, navigating to a screen from within the Sheet can cause issues. To resolve this, dismiss the sheet before navigating!
3640

3741
Example:
38-
```tsx
42+
```tsx {4-5}
3943
const sheet = useRef<TrueSheet>(null)
4044

4145
const navigate = async () => {

example/ios/Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,7 +1214,7 @@ PODS:
12141214
- React-Core
12151215
- react-native-safe-area-context (5.2.0):
12161216
- React-Core
1217-
- react-native-true-sheet (2.0.2):
1217+
- react-native-true-sheet (2.0.3):
12181218
- DoubleConversion
12191219
- glog
12201220
- hermes-engine
@@ -1923,7 +1923,7 @@ SPEC CHECKSUMS:
19231923
React-microtasksnativemodule: 72564d5469003687d39bfc4efad281df8efc0684
19241924
react-native-maps: ee1e65647460c3d41e778071be5eda10e3da6225
19251925
react-native-safe-area-context: 849d7df29ecb2a7155c769c0b76849ba952c2aa3
1926-
react-native-true-sheet: 7fb131224336979607e4d81c523e07f618ae3a71
1926+
react-native-true-sheet: b5cc3652405dd472035b5af191857179c47d56d8
19271927
React-nativeconfig: cb207ebba7cafce30657c7ad9f1587a8f32e4564
19281928
React-NativeModulesApple: 82a8bee52df9f5b378195a500f22be3a6ef0f890
19291929
React-perflogger: 8152bab3f0eb4b8751f282f9af7caed2c823a9ea
Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { View, type ColorValue, type ViewProps, Text, StyleSheet } from 'react-native'
1+
import {
2+
View,
3+
type ColorValue,
4+
type ViewProps,
5+
Text,
6+
type ViewStyle,
7+
type TextStyle,
8+
} from 'react-native'
29
import { BORDER_RADIUS, SPACING } from '../utils'
310

411
interface DemoContentProps extends ViewProps {
@@ -10,25 +17,21 @@ interface DemoContentProps extends ViewProps {
1017
export const DemoContent = (props: DemoContentProps) => {
1118
const { text, radius = BORDER_RADIUS, style: $style, color = 'rgba(0,0,0,0.2)', ...rest } = props
1219
return (
13-
<View
14-
style={[styles.content, { backgroundColor: color, borderRadius: radius }, $style]}
15-
{...rest}
16-
>
17-
{text && <Text style={styles.text}>{text}</Text>}
20+
<View style={[$content, { backgroundColor: color, borderRadius: radius }, $style]} {...rest}>
21+
{text && <Text style={$text}>{text}</Text>}
1822
</View>
1923
)
2024
}
2125

22-
const styles = StyleSheet.create({
23-
content: {
24-
height: 100,
25-
marginBottom: 16,
26-
padding: SPACING / 2,
27-
alignItems: 'center',
28-
},
29-
text: {
30-
fontSize: 16,
31-
lineHeight: 20,
32-
color: 'white',
33-
},
34-
})
26+
const $content: ViewStyle = {
27+
height: 100,
28+
marginBottom: 16,
29+
padding: SPACING / 2,
30+
alignItems: 'center',
31+
}
32+
33+
const $text: TextStyle = {
34+
fontSize: 16,
35+
lineHeight: 20,
36+
color: 'white',
37+
}

example/src/components/sheets/BasicSheet.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { forwardRef, useRef, type Ref, useImperativeHandle } from 'react'
2-
import { StyleSheet } from 'react-native'
2+
import { type ViewStyle } from 'react-native'
33
import { TrueSheet, type TrueSheetProps } from '@lodev09/react-native-true-sheet'
44

55
import { DARK, DARK_BLUE, GRABBER_COLOR, SPACING } from '../../utils'
@@ -44,7 +44,7 @@ export const BasicSheet = forwardRef((props: BasicSheetProps, ref: Ref<TrueSheet
4444
<TrueSheet
4545
sizes={['auto', '80%', 'large']}
4646
ref={sheetRef}
47-
contentContainerStyle={styles.content}
47+
contentContainerStyle={$content}
4848
blurTint="dark"
4949
backgroundColor={DARK}
5050
cornerRadius={12}
@@ -92,7 +92,7 @@ export const BasicSheet = forwardRef((props: BasicSheetProps, ref: Ref<TrueSheet
9292
ref={childSheet}
9393
sizes={['auto']}
9494
backgroundColor={DARK}
95-
contentContainerStyle={styles.content}
95+
contentContainerStyle={$content}
9696
FooterComponent={<Footer />}
9797
>
9898
<DemoContent color={DARK_BLUE} />
@@ -104,10 +104,8 @@ export const BasicSheet = forwardRef((props: BasicSheetProps, ref: Ref<TrueSheet
104104
)
105105
})
106106

107-
BasicSheet.displayName = 'BasicSheet'
107+
const $content: ViewStyle = {
108+
padding: SPACING,
109+
}
108110

109-
const styles = StyleSheet.create({
110-
content: {
111-
padding: SPACING,
112-
},
113-
})
111+
BasicSheet.displayName = 'BasicSheet'

example/src/components/sheets/BlankSheet.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { forwardRef, type Ref } from 'react'
2-
import { StyleSheet, Text } from 'react-native'
2+
import { Text, type ViewStyle } from 'react-native'
33
import { TrueSheet, type TrueSheetProps } from '@lodev09/react-native-true-sheet'
44

55
import { $WHITE_TEXT, DARK, SPACING } from '../../utils'
@@ -16,18 +16,16 @@ export const BlankSheet = forwardRef((props: BlankSheetProps, ref: Ref<TrueSheet
1616
edgeToEdge
1717
backgroundColor={DARK}
1818
keyboardMode="pan"
19-
contentContainerStyle={styles.content}
19+
contentContainerStyle={$content}
2020
{...props}
2121
>
2222
<Text style={$WHITE_TEXT}>Blank Sheet</Text>
2323
</TrueSheet>
2424
)
2525
})
2626

27-
BlankSheet.displayName = 'BlankSheet'
27+
const $content: ViewStyle = {
28+
padding: SPACING,
29+
}
2830

29-
const styles = StyleSheet.create({
30-
content: {
31-
padding: SPACING,
32-
},
33-
})
31+
BlankSheet.displayName = 'BlankSheet'

0 commit comments

Comments
 (0)