Create a hole in react-native webview for touch ev

2020-07-14 12:10发布

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.

1条回答
对你真心纯属浪费
2楼-- · 2020-07-14 12:49

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

查看更多
登录 后发表回答