Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix buttons getting stuck after scrolling on them #2693

Merged
merged 4 commits into from
May 16, 2024

Conversation

j-piasecki
Copy link
Member

@j-piasecki j-piasecki commented Dec 15, 2023

Description

I've noticed a weird interaction between Gesture Handler buttons and the ScrollView wrapped with NativeViewGestureHandler after #2551 - after starting the scroll on a button, that button (and only that one) would become unresponsive for the next touch. The issue is apparent after touching the same button after the scroll ends, where it doesn't react to the first touch (see the before video).

After some debugging, I've found that cancelAndClearTouchTargets was invoked before delivering the event to the children of the GestureHandlerRootView when clicking on the same button. This, in a nutshell, was resulting in the following scenario:

  1. User touches the button, MotionEvent.ACTION_DOWN is dispatched
  2. RootView tries to deliver the event to handlers, Button receives the event and sets lastAction to ACTION_DOWN and lastEventTime.
  3. No handler is active, RootView calls super.dispatchTouchEvent
  4. cancelAndClearTouchTargets is invoked, ACTION_CANCEL event is dispatched to children of the RootView
  5. Button receives the cancel event and processes it internally, touch is cancelled
  6. Original ACTION_DOWN event is dispatched to children of RootView
  7. Button receives the ACTION_DOWN event but it's the same event that it received before the synthetic cancel event - it's the same action and time as saved, so the event is ignored
  8. ACTION_UP event is dispatched when finger is removed from the screen, Button ignores it since there is no press active

This PR changes the logic in the Button component to also save the last action type and time for CANCEL events, so that the second time the DOWN event is delivered, it's not being ignored.

This is effectively a revert of #2586, which was fixing stuff that #1601 broke in a wrong way. Hopefully, this one solves the issue once and for all 🤞.

From the review

You could also consider adding a few words about ScrollView interactions into PR description 😅

When running the reproducer code below, you may notice that the scrolling will be cancelled by the buttons being pressed. This can be avoided by setting disallowInterruption on the native gesture wrapping the ScrollView, which is done by default on the ScrollView exported by RNGH.

Test plan

Tested on the Example app (most notably nested buttons example), code from the issue #2585 and on the following code
import React from 'react';
import { StyleSheet, Text, ScrollView } from 'react-native';
import {
  GestureDetector,
  Gesture,
  RectButton,
  GestureHandlerRootView,
} from 'react-native-gesture-handler';

export const DATA = new Array(100).fill(0).map((_, index) => `Item ${index}`);

export default function App() {
  const scrollGesture = Gesture.Native();

  return (
    <GestureDetector gesture={scrollGesture}>
      <ScrollView>
        <GestureHandlerRootView>
          {DATA.map((genre, index) => (
            <RectButton
              key={index}
              style={styles.selectableItem}
              onPress={() => {
                console.log('Pressed', genre);
              }}>
              <Text style={[styles.genreText, styles.horizontalMargin]}>
                {genre}
              </Text>
            </RectButton>
          ))}
        </GestureHandlerRootView>
      </ScrollView>
    </GestureDetector>
  );
}

export const styles = StyleSheet.create({
  genreText: {
    fontSize: 18,
    fontWeight: '600',
    marginVertical: 12,
  },
  selectableItem: {
    flexDirection: 'row',
    alignItems: 'center',
    paddingHorizontal: 16,
    paddingVertical: 8,
  },
  horizontalMargin: {
    marginHorizontal: 16,
  },
});

Before the change:

Screen.Recording.2023-12-15.at.15.18.25.mov

After the change:

Screen.Recording.2023-12-15.at.15.17.22.mov

j-piasecki added a commit that referenced this pull request Feb 5, 2024
## Description

This is loosely related to
#2693,
as debugging it allowed to find this bug.

Currently when a handler finishes while it's waiting, it only sends
events if it fails or when it gets canceled. If the gesture finishes
successfully, the event is not sent as it's waiting for another one. If
the gesture it's waiting for fails, it goes through all awaiting
handlers and tries to activate them if criteria are met.

Since the gesture it tries to activate is already finished, synthetic
events need to be sent to the JS side to achieve the correct behavior.
Because of that, if the gesture is cancelled while waiting and then the
gesture it waited for fails, GH will try to activate the cancelled
gesture and will send the synthetic events. So the events would look
like this:
1. `UNDETERMINED` -> `BEGAN`
2. `BEGAN` -> `CANCELLED`
3. `BEGAN` -> `ACTIVE`
4. `ACTIVE` -> `ENDED`
5. `ENDED` -> `UNDETERMINED`

I.e. in certain conditions, a gesture could be activated after it was
canceled, this PR simply adds a condition that the gesture cannot be in
`FAILED` or `CANCELLED` state before sending the synthetic events.

## Test plan

<details>
<summary>Tested on the following code in the Example app.</summary>

```jsx
import React, { useRef } from 'react';
import { StyleSheet, Text, ScrollView, View } from 'react-native';
import {
  GestureDetector,
  Gesture,
  RectButton,
  GestureHandlerRootView,
} from 'react-native-gesture-handler';

export const DATA = new Array(100).fill(0).map((_, index) => `Item ${index}`);

function Button({ text, panRef }: any) {
  const [selected, setSelected] = React.useState(false);

  return (
    <RectButton
      waitFor={panRef}
      style={[styles.selectableItem, selected && styles.selectedItem]}
      onHandlerStateChange={(e) => {
        console.log(
          'State change',
          e.nativeEvent.oldState,
          e.nativeEvent.state
        );
      }}
      onPress={() => {
        setSelected(!selected);
        console.log('Pressed', text);
      }}>
      <Text style={[styles.genreText, styles.horizontalMargin]}>{text}</Text>
    </RectButton>
  );
}

export default function App() {
  const panRef = useRef<any>(null);

  const scrollGesture = Gesture.Native();
  const pan = Gesture.Pan().manualActivation(true).withRef(panRef);

  return (
    <GestureDetector gesture={pan}>
      <View style={{ flex: 1 }}>
        <GestureDetector gesture={scrollGesture}>
          <ScrollView>
            <GestureHandlerRootView>
              {DATA.map((text, index) => (
                <Button key={index} text={text} panRef={panRef} />
              ))}
            </GestureHandlerRootView>
          </ScrollView>
        </GestureDetector>
      </View>
    </GestureDetector>
  );
}

export const styles = StyleSheet.create({
  genreText: {
    fontSize: 18,
    fontWeight: '600',
    marginVertical: 12,
  },
  selectableItem: {
    flexDirection: 'row',
    alignItems: 'center',
    paddingHorizontal: 16,
    paddingVertical: 8,
  },
  horizontalMargin: {
    marginHorizontal: 16,
  },
  selectedItem: {
    backgroundColor: '#aaa',
  }
});

```
</details>

Before:


https://github.com/software-mansion/react-native-gesture-handler/assets/21055725/35211c91-544b-4612-9e80-ee8abed9b646

After:


https://github.com/software-mansion/react-native-gesture-handler/assets/21055725/c8b8da6e-aae8-4b09-acca-1286dab6b4fa

---------

Co-authored-by: Michał Bert <63123542+m-bert@users.noreply.github.com>
@j-piasecki j-piasecki requested a review from m-bert May 14, 2024 10:48
Copy link
Contributor

@m-bert m-bert left a comment

Choose a reason for hiding this comment

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

Good job! You could also consider adding a few words about ScrollView interactions into PR description 😅

@j-piasecki j-piasecki merged commit bcd9524 into main May 16, 2024
3 checks passed
@j-piasecki j-piasecki deleted the @jpiasecki/fix-stuck-buttons branch May 16, 2024 09:41
github-merge-queue bot pushed a commit to valora-inc/wallet that referenced this pull request Jun 26, 2024
…5575)

[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[react-native-gesture-handler](https://github.com/software-mansion/react-native-gesture-handler)
| [`^2.16.2` ->
`^2.17.1`](https://renovatebot.com/diffs/npm/react-native-gesture-handler/2.16.2/2.17.1)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/react-native-gesture-handler/2.17.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/react-native-gesture-handler/2.17.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/react-native-gesture-handler/2.16.2/2.17.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/react-native-gesture-handler/2.16.2/2.17.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>software-mansion/react-native-gesture-handler
(react-native-gesture-handler)</summary>

###
[`v2.17.1`](https://github.com/software-mansion/react-native-gesture-handler/releases/tag/2.17.1)

[Compare
Source](https://github.com/software-mansion/react-native-gesture-handler/compare/2.17.0...2.17.1)

#### 🐛 Bug fixes

- Don't register `checkIntegrityBetweenArchitectures` task when
installed as a dependency by
[@&#8203;j-piasecki](https://github.com/j-piasecki) in
[#&#8203;2953](https://github.com/software-mansion/react-native-gesture-handler/issues/2953)

**Full Changelog**:
software-mansion/react-native-gesture-handler@2.17.0...2.17.1

###
[`v2.17.0`](https://github.com/software-mansion/react-native-gesture-handler/releases/tag/2.17.0)

[Compare
Source](https://github.com/software-mansion/react-native-gesture-handler/compare/2.16.2...2.17.0)

#### ❗ Important changes

- Add `ref` property to `Buttons` by
[@&#8203;m-bert](https://github.com/m-bert) in
[software-mansion/react-native-gesture-handler#2903
- Unify touch events callbacks on `web` with respect to `Android` by
[@&#8203;m-bert](https://github.com/m-bert) in
[software-mansion/react-native-gesture-handler#2923
- Add `touchType` to `TouchEvent` by
[@&#8203;latekvo](https://github.com/latekvo) in
[software-mansion/react-native-gesture-handler#2941

#### 👍 Improvements

- Refactor `GestureDetector` by
[@&#8203;j-piasecki](https://github.com/j-piasecki) in
[software-mansion/react-native-gesture-handler#2901
- Remove lodash by [@&#8203;m-bert](https://github.com/m-bert) in
[software-mansion/react-native-gesture-handler#2916
- `PointerTracker` refactor. by
[@&#8203;m-bert](https://github.com/m-bert) in
[software-mansion/react-native-gesture-handler#2931
- Change `offsetX` and `offsetY` calculations in `PointerEventManager`
by [@&#8203;m-bert](https://github.com/m-bert) in
[software-mansion/react-native-gesture-handler#2938

#### 🐛 Bug fixes

- Make `RootViewGestureHandler` handler cancel awaiting gestures by
[@&#8203;j-piasecki](https://github.com/j-piasecki) in
[software-mansion/react-native-gesture-handler#2900
- Get right bridge by
[@&#8203;piaskowyk](https://github.com/piaskowyk) in
[software-mansion/react-native-gesture-handler#2886
- Fix buttons getting stuck after scrolling on them by
[@&#8203;j-piasecki](https://github.com/j-piasecki) in
[software-mansion/react-native-gesture-handler#2693
- Fix Detector creating and attaching all gestures twice on first mount
by [@&#8203;j-piasecki](https://github.com/j-piasecki) in
[software-mansion/react-native-gesture-handler#2914
- Fix GestureDetector not working when its children change by
[@&#8203;j-piasecki](https://github.com/j-piasecki) in
[software-mansion/react-native-gesture-handler#2921
- Fix GestureDetector not working correctly with suspense and recycling
by [@&#8203;j-piasecki](https://github.com/j-piasecki) in
[software-mansion/react-native-gesture-handler#2925
- Fix nested buttons on the new architecture by
[@&#8203;j-piasecki](https://github.com/j-piasecki) in
[software-mansion/react-native-gesture-handler#2926
- Unify scaled coordinates between `web` and `native` side. by
[@&#8203;m-bert](https://github.com/m-bert) in
[software-mansion/react-native-gesture-handler#2943
- \[Web] Send relative coords in event. by
[@&#8203;m-bert](https://github.com/m-bert) in
[software-mansion/react-native-gesture-handler#2944

#### 🔢 Miscellaneous

- Add information about `GestureHandlerRootView` area and change
component name in quick start section in docs. by
[@&#8203;m-bert](https://github.com/m-bert) in
[software-mansion/react-native-gesture-handler#2899
- Add Hire us section to docs by
[@&#8203;patrycjakalinska](https://github.com/patrycjakalinska) in
[software-mansion/react-native-gesture-handler#2904
- Bump ejs from 3.1.7 to 3.1.10 by
[@&#8203;dependabot](https://github.com/dependabot) in
[software-mansion/react-native-gesture-handler#2888
- Bump tar from 6.2.0 to 6.2.1 in /e2e/web-tests by
[@&#8203;dependabot](https://github.com/dependabot) in
[software-mansion/react-native-gesture-handler#2859
- docs: add
[@&#8203;swmansion/t-rex-ui](https://github.com/swmansion/t-rex-ui) by
[@&#8203;kacperkapusciak](https://github.com/kacperkapusciak) in
[software-mansion/react-native-gesture-handler#2895
- Change navbar and footer to a reusable component by
[@&#8203;patrycjakalinska](https://github.com/patrycjakalinska) in
[software-mansion/react-native-gesture-handler#2902
- Add dark mode to button in `Hire us` section by
[@&#8203;patrycjakalinska](https://github.com/patrycjakalinska) in
[software-mansion/react-native-gesture-handler#2908
- Setup example app to use Expo by
[@&#8203;bohdanprog](https://github.com/bohdanprog) in
[software-mansion/react-native-gesture-handler#2905
- Revert "docs: add
[@&#8203;swmansion/t-rex-ui](https://github.com/swmansion/t-rex-ui)"
by [@&#8203;kacperkapusciak](https://github.com/kacperkapusciak) in
[software-mansion/react-native-gesture-handler#2909
- Bump [@&#8203;sideway/formula](https://github.com/sideway/formula)
from 3.0.0 to 3.0.1 by
[@&#8203;dependabot](https://github.com/dependabot) in
[software-mansion/react-native-gesture-handler#2910
- docs: add
[@&#8203;swmansion/t-rex-ui](https://github.com/swmansion/t-rex-ui) by
[@&#8203;patrycjakalinska](https://github.com/patrycjakalinska) in
[software-mansion/react-native-gesture-handler#2911
- Fix symlink loop during pods installation by
[@&#8203;j-piasecki](https://github.com/j-piasecki) in
[software-mansion/react-native-gesture-handler#2917
- Bump rexml from 3.2.6 to 3.2.8 in /FabricExample by
[@&#8203;dependabot](https://github.com/dependabot) in
[software-mansion/react-native-gesture-handler#2915
- Add animated header to the example app by
[@&#8203;j-piasecki](https://github.com/j-piasecki) in
[software-mansion/react-native-gesture-handler#2913
- Add option to auto-open last example in the example app by
[@&#8203;j-piasecki](https://github.com/j-piasecki) in
[software-mansion/react-native-gesture-handler#2918
- Replace current theme components with `@swmansion/t-rex-ui` by
[@&#8203;patrycjakalinska](https://github.com/patrycjakalinska) in
[software-mansion/react-native-gesture-handler#2906
- Bump rexml from 3.2.6 to 3.2.8 in /MacOSExample by
[@&#8203;dependabot](https://github.com/dependabot) in
[software-mansion/react-native-gesture-handler#2924
- Bump rexml from 3.2.6 to 3.2.8 in /example by
[@&#8203;dependabot](https://github.com/dependabot) in
[software-mansion/react-native-gesture-handler#2930
- feat: automatically copy codegen artifacts to paper by
[@&#8203;maciekstosio](https://github.com/maciekstosio) in
[software-mansion/react-native-gesture-handler#2933
- Add swipeable example rewritten to new API by
[@&#8203;latekvo](https://github.com/latekvo) in
[software-mansion/react-native-gesture-handler#2934
- Fix new swipeable using useMemo with incomplete dependency list by
[@&#8203;latekvo](https://github.com/latekvo) in
[software-mansion/react-native-gesture-handler#2937
- docs: update Hire us links to directly lead to contact form by
[@&#8203;kacperkapusciak](https://github.com/kacperkapusciak) in
[software-mansion/react-native-gesture-handler#2935
- chore(types): add missing pointerType to GestureTouchEvent by
[@&#8203;mgcrea](https://github.com/mgcrea) in
[software-mansion/react-native-gesture-handler#2928
- Bump braces from 3.0.2 to 3.0.3 in /example by
[@&#8203;dependabot](https://github.com/dependabot) in
[software-mansion/react-native-gesture-handler#2945
- Bump braces from 3.0.2 to 3.0.3 in /e2e/web-tests by
[@&#8203;dependabot](https://github.com/dependabot) in
[software-mansion/react-native-gesture-handler#2946
- Bump ws from 6.2.2 to 6.2.3 by
[@&#8203;dependabot](https://github.com/dependabot) in
[software-mansion/react-native-gesture-handler#2947
- Bump ws from 6.2.2 to 6.2.3 in /e2e/web-tests by
[@&#8203;dependabot](https://github.com/dependabot) in
[software-mansion/react-native-gesture-handler#2948
- Add `relativeCoords` average to `PointerTracker` by
[@&#8203;m-bert](https://github.com/m-bert) in
[software-mansion/react-native-gesture-handler#2939
- Add missing import in docs by
[@&#8203;piaskowyk](https://github.com/piaskowyk) in
[software-mansion/react-native-gesture-handler#2950

#### New Contributors

- [@&#8203;bohdanprog](https://github.com/bohdanprog) made their first
contribution in
[software-mansion/react-native-gesture-handler#2905
- [@&#8203;maciekstosio](https://github.com/maciekstosio) made their
first contribution in
[software-mansion/react-native-gesture-handler#2933
- [@&#8203;mgcrea](https://github.com/mgcrea) made their first
contribution in
[software-mansion/react-native-gesture-handler#2928

**Full Changelog**:
software-mansion/react-native-gesture-handler@2.16.2...2.17.0

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 5pm,every weekend" in timezone
America/Los_Angeles, Automerge - "after 5pm,every weekend" in timezone
America/Los_Angeles.

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/valora-inc/wallet).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy40MTMuMiIsInVwZGF0ZWRJblZlciI6IjM3LjQxMy4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJucG0iLCJyZW5vdmF0ZSJdfQ==-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: valora-bot <valorabot@valoraapp.com>
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.

2 participants