wix-incubator / react-native-interactable

Experimental implementation of high performance interactable views in React Native
MIT License
5.19k stars 515 forks source link

[Android] Touchables in Interactable.View #187

Open ghost opened 6 years ago

ghost commented 6 years ago

Hello,

I'm currently facing an issue only on Android. When I press a touchable inside an Interactable.View it's never fired. It looks like the views are way more sensitive in Android and I have to press very straight and without moving my finger.

On ios, it's working perfectly

img_8721

Has somebody else faced a similar issue ?

ghost commented 6 years ago

Ok, I searched a long time for a workaround on this issue. I've came to the idea of having all my Interactable.View set as dragEnable={false} so that the touchable inside could easily be pressed.

Then I added an onLongPress on my Touchable that makes my Interactable.View draggable. It is working but the problem now is that when onLongPress is fired, the Interactable.View is correctly set to dragEnabled={true} but it doesn't catch my drag afterwards. I have to remove my finger and then start dragging.

It looks like the TouchableOpacity is catching all the movements after the onLongPress.

Here's my code (simplified for understanding) :

    <Interactable.View
        animatedNativeDriver={true}
        dragEnabled={this.state.editMode}    
    >
        <TouchableOpacity
            onPress={() => alert('Touchable Pressed')}
            onLongPress={() => this.setState({editMode: true})}
        >
            <Text>Test Button</Text>
        </TouchableOpacity>
    </Interactable.View>
victorileaf commented 6 years ago

Any one found a solution for this issue?

ghost commented 6 years ago

I think this issue is not resolvable in any way... It's not wix's issue here but rather how touchables behave in react-native Android. Maybe we should try to develop a module that wraps the native Android Button component.

I'll try to explore more on that next week since this issue stills blocks me.

ghost commented 6 years ago

Ok, I managed to solve my issue by using the React Native Animated library and PanResponder. This is how I did it:

First I created an Animated.ValueXY for my bubble position. It is animated by my PanResponder on Drag. In my onResponderRelease I check if the user dragged more that 3 pixels. If not, I launch the onPress manually by calling .touchableHandlePress() on my TouchableOpacity instance.

By doing it this way, I don't have to worry anymore if my touchable is catching the drag. My PanResponder captures everything. And I chose when the button is actually pressed. I also mimic the button feel by manually setting the opacity on the instance.

const position = new Animated.ValueXY({x: 0, y: 0});
const panResponder = PanResponder.create({
    onStartShouldSetPanResponder: () => true,
    onStartShouldSetPanResponderCapture: (evt, gestureState) => {
        // Set opacity of button to half
        this._touchable.setOpacityTo(0.5, 100);
        // PanResponder always capturing
        return true;
    },
    // At each drag start
    onPanResponderGrant: (evt, gestureState) => {
        // Add offset of last position
        position.setOffset(position.__getValue());
        // Resets to x:0 and y:0
        position.setValue({ x: 0, y: 0 });
    },
    onPanResponderMove: (event, gesture) => {
        // If user drags more that 3px around
        if (gesture.dx > 3 || gesture.dy > 3 || gesture.dy < -3 || gesture.dx < -3) {
            // Start moving the view around
            position.setValue({ x: gesture.dx, y: gesture.dy });
            // Reset button Opacity
            this._touchable.setOpacityTo(1, 100);
        }
    },
    // When the user releases touch
    onPanResponderRelease: (event, gesture) => {
        // If the user didn't move more than 3px around, I consider it as a press on the button
        if (gesture.dx < 3 && gesture.dx > -3 && gesture.dy < 3 && gesture.dy > -3) {
          // Launch button on click
          this._touchable.touchableHandlePress();
          // Reset button opacity 
          this._touchable.setOpacityTo(1, 100);
        }
    }
});

My component :

<Animated.View
    style={...this.state.position.getLayout()}
    {...this.state.panResponder.panHandlers}
 >
    <TouchableOpacity
        onPress={() => alert("Click")}
        ref={(touchable) => this._touchable = touchable}
        style={styles.littleCircle}
    />
</Animated.View>

I also recreated the SnapPoints system but no need to show it here. HMU if anybody wants a gist

iLeafSolutionsPvtLtd commented 6 years ago

Thanks a lot bro ... I was starting to implement this using animated .. can u share the gist?

victorkvarghese commented 6 years ago

@Deevent Can u share the code?

ghost commented 6 years ago

@victorileaf @victorkvarghese Sure ! Here's the link to the gist and how I managed to do it : https://gist.github.com/Deevent/6300fb3531e6e526a880a82b98c049a6

koloff commented 6 years ago

Thank you, @Deevent! But how can we drag the interactable, if the view inside it captures all events?

afresh commented 6 years ago

@victorileaf @victorkvarghese Sure ! Here's the link to the gist and how I managed to do it : https://gist.github.com/Deevent/6300fb3531e6e526a880a82b98c049a6

@Deevent How to use the Bubble? Could you provide a demo?

afresh commented 6 years ago

Please use react-native-interactable-button instead. It solves the conflict between dragging events and clicking events. https://github.com/afresh/react-native-interactable-button

woodpav commented 6 years ago

Does anyone know what this is caused by? I'm trying to fix the java code.

victorkvarghese commented 6 years ago

I searched everywhere ..almost everyone said the same ..

It's not wix's issue here but rather how touchables behave in react-native Android. Couldn't go deep into why this happens though...

woodpav commented 6 years ago

Are there any resources you can point me towards?

victorkvarghese commented 6 years ago

I tried another lib.. react native gesture handler.. there is a chat heads functionality .. it works flawlessly on iOS but issues with Android.

https://github.com/kmagiera/react-native-gesture-handler/tree/master/Example/chatHeads

woodpav commented 6 years ago

Solid link, I didn't know about that repo. I managed to fix this issue in my fork. Tested on a physical device. Additional issues are welcome over there.

woodpav/react-native-interactable

victorkvarghese commented 6 years ago

@woodpav .. what's was the issue .. ? Can you explain how you fixed it if possible..

woodpav commented 6 years ago

https://github.com/woodpav/react-native-interactable/commit/d16900040a6762aec06740fe3fe6020f3aa25b6e#commitcomment-31130791

dopey2 commented 5 years ago

is this merged in master ?

woodpav commented 5 years ago

@dopey2 I dont think so. Take a look at this PR https://github.com/wix/react-native-interactable/pull/253

dopey2 commented 5 years ago

@woodpav can you publish your own fork on npm?

woodpav commented 5 years ago

@dopey2 https://www.npmjs.com/package/react-native-interactive

parohy commented 5 years ago

Android only. This is still an issue. The PR adding this.isSwiping into the condition on android did not change the behavior. Touch events fall over to view under the intractable. We have a ScrollView and an intractable player which can be expanded. When expanded, the controls in it doesn't react on touch events at all. Touch events are being triggered on the ScrollView. Drag is not working as well.

JakeHadley commented 5 years ago

@woodpav What exactly does your fork solve? I'm looking to avoid the bugs being described in these issues...

woodpav commented 5 years ago

It fixes Touchables on Android and a few other things if I remember right. With my fork I am not experiencing the issues @parohy mentioned. That said I recently moved away from this package in favor of PanResponder. This package needs to be updated to AndroidX for react-native 0.60+ and PanResponder tends to be more stable given that it is officially maintained. I also noticed that PanResponder onMove is slightly faster than adding a listener to the Interactive.View animatedValue. If you really want to use this package, I suggest my fork. If you're unsure, try to get PanResponder working. Furthermore, due to Interactive.View API decisions I noticed that PanResponder implementions use ~50% less code for my use case.

JakeHadley commented 5 years ago

Ok, I'm basically looking to implement the google maps bottom sheet type thing. And wix had that as one of their examples. But the Interactable would require a scrollview while being able to move vertically as a whole. Do you think yours would allow for that type of implementation?

As for the PanResponder, do you think it would be too difficult to do this myself with it?

woodpav commented 5 years ago

I have tried a lot of implementations to do a very similar thing. I finally settled on a PanRepsonder in a ScrollView. Using this package works but the bugs are numerous especially because of the way Android captures touches and this package intercepts them. You'll run into problems with ScrollView like others are running into issues with Touchables. Feel free to send me some code and we can discuss further. My email is devwoodpav@gmail.com.

woodpav commented 5 years ago

@JakeHadley Alternatively you can send me stuff on GitHub so others can gain from our learnings. You can open an issue in my repo and we can reference it here so others in this thread don't get extra notifications.

https://github.com/woodpav/react-native-interactive/issues/2

JakeHadley commented 5 years ago

I'll do that. I'll use your repo and see what happens and open an issue.

JakeHadley commented 5 years ago

@woodpav Issue created.

ShaharyarMaroof commented 4 years ago

hey @parohy I am also facing a similar issue on Android. did you manage to fix it?

manpreetsingh3215 commented 4 years ago

Hey!, to fix this issue please go to this file node_modules/react-native-interactable/lib/android/src/main/java/com/wix/interactable/InteractableView.java

and add this , reference is in this image

Screenshot 2020-07-25 at 1 34 03 PM

thanks, may be it would help