Skip to content

Commit 14190fc

Browse files
authored
Merge branch '@akwasniewski/native-detector-web' into @akwasniewski/v3-web-typing
2 parents cc3b639 + dceba3b commit 14190fc

35 files changed

+337
-176
lines changed

apps/basic-example/src/NativeDetector.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ export default function App() {
1818
);
1919

2020
const gesture = useGesture('PanGestureHandler', {
21-
onGestureHandlerAnimatedEvent: event,
22-
onGestureHandlerEvent: (e: any) =>
23-
console.log('onGestureHandlerEvent', e.nativeEvent),
21+
onUpdate: event,
2422
});
2523

2624
return (

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import com.facebook.react.bridge.WritableArray
1818
import com.facebook.react.uimanager.PixelUtil
1919
import com.swmansion.gesturehandler.BuildConfig
2020
import com.swmansion.gesturehandler.RNSVGHitTester
21+
import com.swmansion.gesturehandler.react.RNGestureHandlerDetectorView
2122
import com.swmansion.gesturehandler.react.RNGestureHandlerTouchEvent
2223
import com.swmansion.gesturehandler.react.eventbuilders.GestureHandlerEventDataBuilder
2324
import java.lang.IllegalStateException
@@ -30,6 +31,22 @@ open class GestureHandler {
3031
var tag = 0
3132
var view: View? = null
3233
private set
34+
val viewForEvents: RNGestureHandlerDetectorView
35+
get() {
36+
assert(actionType == ACTION_TYPE_NATIVE_DETECTOR) {
37+
"[react-native-gesture-handler] `viewForEvents` can only be used with NativeDetector."
38+
}
39+
40+
val detector = if (this is NativeViewGestureHandler) this.view?.parent else view
41+
42+
if (detector !is RNGestureHandlerDetectorView) {
43+
throw Error(
44+
"[react-native-gesture-handler] Expected RNGestureHandlerDetectorView to be the target for the event.",
45+
)
46+
}
47+
48+
return detector
49+
}
3350
var state = STATE_UNDETERMINED
3451
private set
3552
var x = 0f
@@ -823,6 +840,8 @@ open class GestureHandler {
823840
}
824841
}
825842

843+
open fun wantsToAttachDirectlyToView() = false
844+
826845
override fun toString(): String {
827846
val viewString = if (view == null) null else view!!.javaClass.simpleName
828847
return this.javaClass.simpleName + "@[" + tag + "]:" + viewString

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/NativeViewGestureHandler.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ class NativeViewGestureHandler : GestureHandler() {
167167
this.hook = defaultHook
168168
}
169169

170+
override fun wantsToAttachDirectlyToView() = true
171+
170172
class Factory : GestureHandler.Factory<NativeViewGestureHandler>() {
171173
override val type = NativeViewGestureHandler::class.java
172174
override val name = "NativeViewGestureHandler"

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorView.kt

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.swmansion.gesturehandler.react
22

33
import android.content.Context
4+
import android.view.View
45
import com.facebook.react.bridge.ReadableArray
56
import com.facebook.react.uimanager.ThemedReactContext
67
import com.facebook.react.uimanager.UIManagerHelper
@@ -12,9 +13,9 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
1213
private val reactContext: ThemedReactContext
1314
get() = context as ThemedReactContext
1415
private var handlersToAttach: List<Int>? = null
15-
private var attachedHandlers = listOf<Int>()
16+
private var nativeHandlersToAttach: MutableSet<Int> = mutableSetOf()
17+
private var attachedHandlers: MutableSet<Int> = mutableSetOf()
1618
private var moduleId: Int = -1
17-
private var dispatchesAnimatedEvents: Boolean = false
1819

1920
fun setHandlerTags(handlerTags: ReadableArray?) {
2021
val newHandlers = handlerTags?.toArrayList()?.map { (it as Double).toInt() } ?: emptyList()
@@ -36,8 +37,24 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
3637
handlersToAttach = null
3738
}
3839

39-
fun setDispatchesAnimatedEvents(dispatchesAnimatedEvents: Boolean) {
40-
this.dispatchesAnimatedEvents = dispatchesAnimatedEvents
40+
private fun shouldAttachGestureToChildView(tag: Int): Boolean {
41+
val registry = RNGestureHandlerModule.registries[moduleId]
42+
?: throw Exception("Tried to access a non-existent registry")
43+
44+
return registry.getHandler(tag)?.wantsToAttachDirectlyToView() ?: false
45+
}
46+
47+
// We override this `addView` because it is called inside `addView(child: View?, index: Int)`
48+
override fun addView(child: View, index: Int, params: LayoutParams?) {
49+
super.addView(child, index, params)
50+
51+
tryAttachHandlerToChildView(child.id)
52+
}
53+
54+
override fun removeViewAt(index: Int) {
55+
detachNativeGestureHandlers()
56+
57+
super.removeViewAt(index)
4158
}
4259

4360
private fun attachHandlers(newHandlers: List<Int>) {
@@ -55,15 +72,53 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
5572
}
5673

5774
for (entry in changes) {
75+
val tag = entry.key
76+
5877
if (entry.value == GestureHandlerMutation.Attach) {
59-
// TODO: Attach to the child when attached gesture is a NativeGestureHandler, track children changes then
60-
registry.attachHandlerToView(
61-
entry.key,
62-
this.id,
63-
GestureHandler.ACTION_TYPE_NATIVE_DETECTOR,
64-
)
78+
// It might happen that `attachHandlers` will be called before children are added into view hierarchy. In that case we cannot
79+
// attach `NativeViewGestureHandlers` here and we have to do it in `addView` method.
80+
if (shouldAttachGestureToChildView(tag)) {
81+
nativeHandlersToAttach.add(tag)
82+
} else {
83+
registry.attachHandlerToView(tag, this.id, GestureHandler.ACTION_TYPE_NATIVE_DETECTOR)
84+
85+
attachedHandlers.add(tag)
86+
}
6587
} else if (entry.value == GestureHandlerMutation.Detach) {
66-
registry.detachHandler(entry.key)
88+
registry.detachHandler(tag)
89+
attachedHandlers.remove(tag)
90+
}
91+
}
92+
93+
// This covers the case where `NativeViewGestureHandlers` are attached after child views were created.
94+
val child = getChildAt(0)
95+
96+
if (child != null) {
97+
tryAttachHandlerToChildView(child.id)
98+
}
99+
}
100+
101+
private fun tryAttachHandlerToChildView(childId: Int) {
102+
val registry = RNGestureHandlerModule.registries[moduleId]
103+
?: throw Exception("Tried to access a non-existent registry")
104+
105+
for (tag in nativeHandlersToAttach) {
106+
registry.attachHandlerToView(tag, childId, GestureHandler.ACTION_TYPE_NATIVE_DETECTOR)
107+
108+
attachedHandlers.add(tag)
109+
}
110+
111+
nativeHandlersToAttach.clear()
112+
}
113+
114+
private fun detachNativeGestureHandlers() {
115+
val registry = RNGestureHandlerModule.registries[moduleId]
116+
?: throw Exception("Tried to access a non-existent registry")
117+
118+
for (tag in attachedHandlers) {
119+
if (shouldAttachGestureToChildView(tag)) {
120+
registry.detachHandler(tag)
121+
attachedHandlers.remove(tag)
67122
}
68123
}
69124
}

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerDetectorViewManager.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,4 @@ class RNGestureHandlerDetectorViewManager :
3636
override fun setModuleId(view: RNGestureHandlerDetectorView, value: Int) {
3737
view.setModuleId(value)
3838
}
39-
40-
override fun setDispatchesAnimatedEvents(view: RNGestureHandlerDetectorView, value: Boolean) {
41-
view.setDispatchesAnimatedEvents(value)
42-
}
4339
}

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEvent.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,14 @@ class RNGestureHandlerEvent private constructor() : Event<RNGestureHandlerEvent>
3333
dataBuilder: GestureHandlerEventDataBuilder<T>,
3434
useNativeAnimatedName: Boolean,
3535
) {
36-
val view = handler.view!!
36+
val view = if (handler.actionType == GestureHandler.ACTION_TYPE_NATIVE_DETECTOR) {
37+
handler.viewForEvents!!
38+
} else {
39+
handler.view!!
40+
}
41+
3742
super.init(UIManagerHelper.getSurfaceId(view), view.id)
43+
3844
this.actionType = actionType
3945
this.dataBuilder = dataBuilder
4046
this.useTopPrefixedName = useNativeAnimatedName

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEventDispatcher.kt

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -78,26 +78,23 @@ class RNGestureHandlerEventDispatcher(private val reactApplicationContext: React
7878
sendEventForDeviceEvent(RNGestureHandlerEvent.EVENT_NAME, data)
7979
}
8080
GestureHandler.ACTION_TYPE_NATIVE_DETECTOR -> {
81-
val view = handler.view
82-
83-
if (view is RNGestureHandlerDetectorView) {
84-
if (handler.dispatchesAnimatedEvents) {
85-
val animatedEvent = RNGestureHandlerEvent.obtain(
86-
handler,
87-
handler.actionType,
88-
handlerFactory.createEventBuilder(handler),
89-
true,
90-
)
91-
view.dispatchEvent(animatedEvent)
92-
}
93-
94-
val event = RNGestureHandlerEvent.obtain(
81+
if (handler.dispatchesAnimatedEvents) {
82+
val animatedEvent = RNGestureHandlerEvent.obtain(
9583
handler,
9684
handler.actionType,
9785
handlerFactory.createEventBuilder(handler),
86+
true,
9887
)
99-
view.dispatchEvent(event)
88+
handler.viewForEvents!!.dispatchEvent(animatedEvent)
10089
}
90+
91+
val event = RNGestureHandlerEvent.obtain(
92+
handler,
93+
handler.actionType,
94+
handlerFactory.createEventBuilder(handler),
95+
)
96+
97+
handler.viewForEvents!!.dispatchEvent(event)
10198
}
10299
}
103100
}
@@ -156,17 +153,15 @@ class RNGestureHandlerEventDispatcher(private val reactApplicationContext: React
156153
}
157154

158155
GestureHandler.ACTION_TYPE_NATIVE_DETECTOR -> {
159-
val view = handler.view
160-
if (view is RNGestureHandlerDetectorView) {
161-
val event = RNGestureHandlerStateChangeEvent.obtain(
162-
handler,
163-
newState,
164-
oldState,
165-
handler.actionType,
166-
handlerFactory.createEventBuilder(handler),
167-
)
168-
view.dispatchEvent(event)
169-
}
156+
val event = RNGestureHandlerStateChangeEvent.obtain(
157+
handler,
158+
newState,
159+
oldState,
160+
handler.actionType,
161+
handlerFactory.createEventBuilder(handler),
162+
)
163+
164+
handler.viewForEvents!!.dispatchEvent(event)
170165
}
171166
}
172167
}
@@ -199,11 +194,9 @@ class RNGestureHandlerEventDispatcher(private val reactApplicationContext: React
199194
sendEventForDeviceEvent(RNGestureHandlerEvent.EVENT_NAME, data)
200195
}
201196
GestureHandler.ACTION_TYPE_NATIVE_DETECTOR -> {
202-
val view = handler.view
203-
if (view is RNGestureHandlerDetectorView) {
204-
val event = RNGestureHandlerTouchEvent.obtain(handler, handler.actionType)
205-
view.dispatchEvent(event)
206-
}
197+
val event = RNGestureHandlerTouchEvent.obtain(handler, handler.actionType)
198+
199+
handler.viewForEvents!!.dispatchEvent(event)
207200
}
208201
}
209202
}

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerStateChangeEvent.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,14 @@ class RNGestureHandlerStateChangeEvent private constructor() : Event<RNGestureHa
2727
actionType: Int,
2828
dataBuilder: GestureHandlerEventDataBuilder<T>,
2929
) {
30-
val view = handler.view!!
30+
val view = if (handler.actionType == GestureHandler.ACTION_TYPE_NATIVE_DETECTOR) {
31+
handler.viewForEvents!!
32+
} else {
33+
handler.view!!
34+
}
35+
3136
super.init(UIManagerHelper.getSurfaceId(view), view.id)
37+
3238
this.dataBuilder = dataBuilder
3339
this.newState = newState
3440
this.oldState = oldState

packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerTouchEvent.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,14 @@ class RNGestureHandlerTouchEvent private constructor() : Event<RNGestureHandlerT
1313
private var actionType = GestureHandler.ACTION_TYPE_JS_FUNCTION_NEW_API
1414

1515
private fun <T : GestureHandler> init(handler: T, actionType: Int) {
16-
val view = handler.view!!
16+
val view = if (handler.actionType == GestureHandler.ACTION_TYPE_NATIVE_DETECTOR) {
17+
handler.viewForEvents!!
18+
} else {
19+
handler.view!!
20+
}
21+
1722
super.init(UIManagerHelper.getSurfaceId(view), view.id)
23+
1824
extraData = createEventData(handler)
1925
coalescingKey = handler.eventCoalescingKey
2026
this.actionType = actionType

packages/react-native-gesture-handler/apple/Handlers/RNNativeViewHandler.mm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,11 @@ - (void)handleTouchCancel:(UIView *)sender forEvent:(UIEvent *)event
229229
withExtraData:[RNGestureHandlerEventExtraData forPointerInside:NO withPointerType:_pointerType]];
230230
}
231231

232+
- (BOOL)wantsToAttachDirectlyToView
233+
{
234+
return YES;
235+
}
236+
232237
#else
233238

234239
- (RNGestureHandlerEventExtraData *)eventExtraData:(RNDummyGestureRecognizer *)recognizer

0 commit comments

Comments
 (0)