Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a hole in react-native webview for touch events

Tags:

We are trying to repeat the same thing that was done is this plugin: https://github.com/mapsplugin/cordova-plugin-googlemaps/blob/master/README.md (How does this plugin work) but using react-native + mapbox gl(native).

The idea is simple: webview and mapview are "siblings", webview is above mapview and part of webview is transparent and mapview is shown under it. We would like any touch events that occur in this transparent area not to be captured by webview and bubble/whatever to mapview so you can touch/drag/zoom map.

Simply said: we want part(not all of it) of webview not to capture events, but to allow underlying view to capture them.

It looks like there are some methods in react native that allow to do that(conditionally control event capture) (https://facebook.github.io/react-native/docs/view.html#onstartshouldsetrespondercapture ) but we can't find any working example to test it and we can't completely understand documentation that is provided (we can't even understand should this callback be specified for parent view or child views).

So basically we just need some instrument in react-native to conditionally capture touch events.

Can anyone help us with it? Example with map/webview may be too complicated, any conditional capture of events in two views should help a lot.

like image 577
XzKto Avatar asked Jan 15 '18 18:01

XzKto


People also ask

How do you get touch events in React Native?

Each touch event is automatically logged as a breadcrumb and displays on the dashboard when an event occurs along with the component tree in which the touch event occurred. This component tree is logged using the name property of a component. By default, React Native will set this property automatically on components.

How do I use pointerEvents in React Native?

js */ import React from "react"; import { Button, StyleSheet, Text, View } from "react-native"; function App() { const getDeviceType = (e) => { console. log(e); }; return ( <View style={styles. app} pointerEvents="box-none"> <View style={styles. header}> <Text style={styles.

Does React Native use WebViews?

React Native uses a JavaScript runtime, but the UI is not HTML and it doesn't use a WebView. You use JSX and React Native specific components to define the UI. It provides a native-level performance and look and feel but some UI parts have to be configured separately for iOS and Android.

How does React Native interact with WebView?

Import the React Native WebView package in App. js . We will create a normal HTML page in WebView and use “script” tags to let the HTML page communicate with the React Native app. In the “script” tag, we are going to call a sendDataToReactNativeApp() function in which we will use a window property called window.


1 Answers

I am not sure if this is the perfect solution but what you can do is to create an EvenEmitter and just make the Webview catch all of the clicks. The ones that should be handled by the Map, can me sent to the map itself.

I use them on screens, where multiple components might be created but they can be emitted to the parent screen. It is mostly used to handle modal screens.

import EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter';

this._eventEmitter = new EventEmitter();

        this._eventEmitter.addListener('modal', (data) => {
            this.setState({
                visibleModal: true,
                modalData: data
            });
        });

Then you can use them like emitter.emit("modal", data)

Edit:

Here is another approach, which also shows you how you can use the methods you were asking in the question.

class Class extends Component {

    onStartShouldSetResponder = () => true;
    onEvent = (e) => {
        let object = {};
        object.locationX = e.nativeEvent.locationX;
        object.locationY = e.nativeEvent.locationY;
        object.pageY = e.nativeEvent.pageY;
        object.pageX = e.nativeEvent.pageX;
        object.target = e.nativeEvent.target;
        //object.touches = e.nativeEvent.touches; //These will trigger a cyclic error while parsing but you can access them
        //object.changedTouches = e.nativeEvent.changedTouches;
        object.identifier = e.nativeEvent.identifier;
        alert(JSON.stringify(object));

        if (object.pageX > this.state.x && object.pageX < (this.state.x + this.state.width) && object.pageY > this.state.y && object.pageY < (this.state.y + this.state.height))
            alert("inside") //Here you can trigger whatever function you need from the underlying view
    }

    onLayout = (event) => {
        this.setState({
            x: event.nativeEvent.layout.x,
            y: event.nativeEvent.layout.y,
            width: event.nativeEvent.layout.width,
            height: event.nativeEvent.layout.height,
        });
    }

    render(){

        return(    

            <ScrollView>

            <View ref={"target"} style={{
                position: 'absolute',
                height: 200,
                width: 200,
                left: 100,
                top: 100,
                backgroundColor: 'rgba(0,0,0,0.5)'
            }}
            onLayout={this.onLayout}
            />

            <View 
            onl
            onStartShouldSetResponder={this.onStartShouldSetResponder} 
            onResponderMove={this.onEvent}
            style={{
                backgroundColor: 'rgba(255,0,0,0.3)',
                width: '100%',
                height: 150
            }}/>

            <TouchableWithoutFeedback 
            onPress={this.onEvent}
            onLongPress={this.onEvent}
            style={{
                backgroundColor: 'rgba(0,255,0,0.3)',
                width: '100%',
                height: 150
            }}> 
            <View style={{height: 150, backgroundColor: 'rgba(0,255,0,0.3)'}}/>
            </TouchableWithoutFeedback>

            <View 
            onTouchStart={this.onEvent}
            onTouchEnd={this.onEvent}
            style={{
                backgroundColor: 'rgba(0,0,255,0.3)',
                width: '100%',
                height: 150
            }}> 
            </View>

            </ScrollView>

        );
    }

}

Maybe this will help you pass events to the other views

like image 50
sebastianf182 Avatar answered Sep 20 '22 12:09

sebastianf182