Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
* [com.swmansion.gesturehandler.NativeViewGestureHandler.onHandle] */
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent): Boolean {
if (event.action == MotionEvent.ACTION_CANCEL) {
tryFreeingResponder()
}

val eventTime = event.eventTime
val action = event.action
// always true when lastEventTime or lastAction have default value (-1)
Expand Down Expand Up @@ -267,7 +271,7 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
}

override fun drawableHotspotChanged(x: Float, y: Float) {
if (responder == null || responder === this) {
if (touchResponder == null || touchResponder === this) {
super.drawableHotspotChanged(x, y)
}
}
Expand All @@ -280,19 +284,31 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
return isResponder
}

override fun afterGestureEnd(event: MotionEvent) {
tryFreeingResponder()
isTouched = false
}

private fun tryFreeingResponder() {
if (touchResponder === this) {
touchResponder = null
soundResponder = this
}
}

private fun tryGrabbingResponder(): Boolean {
if (isChildTouched()) {
return false
}

if (responder == null) {
responder = this
if (touchResponder == null) {
touchResponder = this
return true
}
return if (exclusive) {
responder === this
touchResponder === this
} else {
!(responder?.exclusive ?: false)
!(touchResponder?.exclusive ?: false)
}
}

Expand All @@ -313,7 +329,8 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
override fun performClick(): Boolean {
// don't preform click when a child button is pressed (mainly to prevent sound effect of
// a parent button from playing)
return if (!isChildTouched()) {
return if (!isChildTouched() && soundResponder == this) {
soundResponder = null
super.performClick()
} else {
false
Expand All @@ -327,22 +344,23 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R
// when canStart is called eventually, tryGrabbingResponder will return true if the button
// already is a responder
if (pressed) {
tryGrabbingResponder()
if (tryGrabbingResponder()) {
soundResponder = this
}
}

// button can be pressed alongside other button if both are non-exclusive and it doesn't have
// any pressed children (to prevent pressing the parent when children is pressed).
val canBePressedAlongsideOther = !exclusive && responder?.exclusive != true && !isChildTouched()
val canBePressedAlongsideOther = !exclusive && touchResponder?.exclusive != true && !isChildTouched()

if (!pressed || responder === this || canBePressedAlongsideOther) {
if (!pressed || touchResponder === this || canBePressedAlongsideOther) {
// we set pressed state only for current responder or any non-exclusive button when responder
// is null or non-exclusive, assuming it doesn't have pressed children
isTouched = pressed
super.setPressed(pressed)
}
if (!pressed && responder === this) {
if (!pressed && touchResponder === this) {
// if the responder is no longer pressed we release button responder
responder = null
isTouched = false
}
}
Expand All @@ -354,7 +372,8 @@ class RNGestureHandlerButtonViewManager : ViewGroupManager<ButtonViewGroup>(), R

companion object {
var resolveOutValue = TypedValue()
var responder: ButtonViewGroup? = null
var touchResponder: ButtonViewGroup? = null
var soundResponder: ButtonViewGroup? = null
var dummyClickListener = OnClickListener { }
}
}
Expand Down
5 changes: 5 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { TouchablesIndex, TouchableExample } from './release_tests/touchables';
import Rows from './release_tests/rows';
import Fling from './release_tests/fling';
import NestedTouchables from './release_tests/nestedTouchables';
import NestedButtons from './release_tests/nestedButtons';
import NestedGestureHandlerRootViewWithModal from './release_tests/nestedGHRootViewWithModal';
import { PinchableBox } from './recipes/scaleAndRotate';
import PanAndScroll from './recipes/panAndScroll';
Expand Down Expand Up @@ -99,6 +100,10 @@ const EXAMPLES: ExamplesSection[] = [
name: 'Nested Touchables - issue #784',
component: NestedTouchables as React.ComponentType,
},
{
name: 'Nested buttons (sound & ripple on Android)',
component: NestedButtons,
},
{ name: 'Double pinch & rotate', component: DoublePinchRotate },
{ name: 'Double draggable', component: DoubleDraggable },
{ name: 'Rows', component: Rows },
Expand Down
85 changes: 85 additions & 0 deletions example/src/release_tests/nestedButtons/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react';
import { View } from 'react-native';

import { RectButton } from 'react-native-gesture-handler';

export default function Example() {
return (
<View style={{ flex: 1 }}>
<RectButton
style={{ width: 400, height: 800, backgroundColor: 'yellow' }}>
<RectButton style={{ width: 375, height: 700, backgroundColor: 'red' }}>
<RectButton
style={{ width: 350, height: 650, backgroundColor: 'green' }}>
<RectButton
style={{
width: 325,
height: 600,
backgroundColor: 'blue',
}}>
<RectButton
style={{ width: 300, height: 550, backgroundColor: 'cyan' }}>
<RectButton
style={{
width: 275,
height: 500,
backgroundColor: 'purple',
}}>
<RectButton
style={{
width: 250,
height: 450,
backgroundColor: 'orange',
}}>
<RectButton
style={{
width: 225,
height: 400,
backgroundColor: 'gray',
}}>
<RectButton
style={{
width: 200,
height: 350,
backgroundColor: 'magenta',
}}>
<RectButton
style={{
width: 175,
height: 300,
backgroundColor: 'wheat',
}}>
<RectButton
style={{
width: 150,
height: 250,
backgroundColor: 'pink',
}}>
<RectButton
style={{
width: 125,
height: 200,
backgroundColor: 'lightgreen',
}}>
<RectButton
style={{
width: 100,
height: 150,
backgroundColor: 'navy',
}}
/>
</RectButton>
</RectButton>
</RectButton>
</RectButton>
</RectButton>
</RectButton>
</RectButton>
</RectButton>
</RectButton>
</RectButton>
</RectButton>
</RectButton>
</View>
);
}
6 changes: 3 additions & 3 deletions example/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3699,9 +3699,9 @@
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==

"@types/react-native@^0.69.6":
version "0.69.6"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.69.6.tgz#b792b7eb024a14869fdbbe97536e6014cb3be731"
integrity sha512-jx1QdJT3CdQc42EpoIGu22F1wrPZjmC/CNkfR5sRs5GxloJzthuICK7CKqAGEo2SekPs+YYzhbzrJGi1IrG5Lg==
version "0.69.13"
resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.69.13.tgz#f947b2bd00439126f8101441945739698bb5051e"
integrity sha512-jEKIkqKjmYI7NeRssLrn/zRtFeI6S1FNe5p45OKbBxrQArXpF2lJelztFTEZKIv1PSfYKcAk5x6+1sdZFEFAkA==
dependencies:
"@types/react" "*"

Expand Down