Создайте дыру в интерактивном веб-просмотре для сенсорных событий

Мы пытаемся повторить то же самое, что и этот плагин: https://github.com/mapsplugin/cordova-plugin-googlemaps/blob/master/README.md (как работает этот плагин), но с использованием react-native + mapbox gl(native).

Идея проста: webview и mapview являются "родными братьями", webview выше mapview, а часть webview прозрачна, а mapview показывается под ним. Мы хотели бы, чтобы любые события касания, которые происходят в этой прозрачной области, не регистрировались веб-просмотром и всплывающими окнами или чем-либо еще в отображении карты, чтобы вы могли касаться/перетаскивать/масштабировать карту.

Проще говоря: мы хотим, чтобы часть (не вся) веб-просмотра не перехватывала события, а позволяла базовому представлению перехватывать их.

Похоже, что в React Native есть несколько методов, которые позволяют это делать (условно управлять захватом событий) (https://facebook.github.io/react-native/docs/view.html#onstartshouldsetrespondercapture ), но мы не можем найти ни одного рабочего примера для его проверки и не можем полностью понять предоставленная документация (мы даже не можем понять, должен ли этот обратный вызов быть указан для родительского представления или дочерних представлений).

Итак, в основном нам просто нужен какой-то инструмент в React-Native для условного захвата событий касания.

Может ли кто-нибудь помочь нам с этим? Пример с картой/веб-представлением может быть слишком сложным, любой условный захват событий в двух представлениях должен сильно помочь.


person XzKto    schedule 15.01.2018    source источник
comment
Вы когда-нибудь находили (полное) решение?   -  person Tafel    schedule 17.06.2021


Ответы (1)


Я не уверен, что это идеальное решение, но вы можете создать EvenEmitter и просто заставить Webview перехватывать все клики. Те, которые должны обрабатываться картой, могут быть отправлены на саму карту.

Я использую их на экранах, где можно создать несколько компонентов, но их можно вывести на родительский экран. Он в основном используется для обработки модальных экранов.

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

this._eventEmitter = new EventEmitter();

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

Затем вы можете использовать их, например, emitter.emit("modal", data)

Редактировать:

Вот еще один подход, который также показывает вам, как вы можете использовать методы, которые вы задавали в вопросе.

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>

        );
    }

}

Возможно, это поможет вам передавать события другим представлениям.

person sfratini    schedule 17.01.2018
comment
Спасибо за ваш ответ! Я тоже играл с этой идеей, но не могу найти подходящей библиотеки, которая могла бы правильно передавать не только само событие, но и все правильные метаданные: координаты клика и т. д. Также на карте есть некоторые сложные события, такие как масштабирование и т. д., и у меня есть опасения по поводу использования этих жестов вручную. Можете ли вы порекомендовать какую-нибудь библиотеку реагирования, которая может это сделать? - person XzKto; 18.01.2018
comment
Ваша установка может стать очень сложной. Можете ли вы описать немного больше вашего варианта использования? Я имею в виду, что вы можете использовать компонент карты из react-native-maps и расширить его, или у вас может быть веб-просмотр с абсолютным положением над картой с небольшой шириной и высотой и т. д. - person sfratini; 18.01.2018
comment
Недавно мы сделали приложение для недвижимости с помощью Cordova. Он довольно большой с большим количеством различных компонентов с двумя основными разделами: поиск клиентов по списку и поддержка клиентов (рекомендации, аналитика и т. д.). Он очень хорошо работает на платформе iOS (iphone6 ​​и выше) и на новых устройствах Android, но старые устройства Android имеют слабые процессоры и поддержку WebGL. Итак, теперь мы думаем переместить некоторые компоненты, которые у нас есть (карта, списки и т. д.), в собственные элементы, сохраняя при этом все остальные (многие!) компоненты в WebView. Теперь, конечно, мы можем полностью перенести некоторые маршруты на Native... ›далее - person XzKto; 18.01.2018
comment
но, к сожалению, на этих маршрутах много модальных окон (полный список модальных окон, фильтры и т. д.), и потребуется много работы, чтобы полностью перевести эти маршруты в Native. Итак, мы хотим сделать такой гибрид - мы знаем точный прямоугольник (координаты) на экране, где должен отображаться собственный компонент, и хотим, чтобы они отображались под нашим WebView, чтобы иметь возможность открывать разные модальные окна с готовой анимацией поверх Это. - person XzKto; 18.01.2018
comment
ммм, я считаю, что вам следует начать с миграции на каждый экран. Существует хороший пакет React-native-maps, созданный AirBnb, и вы можете использовать пользовательские выноски или указатели, чтобы вы могли поймать там некоторые события касания. Что касается модальных окон, возможно, у вас действительно есть модальное окно RN, которое в основном представляет собой веб-просмотр, куда вы можете загружать существующие модальные окна. На мой взгляд, вам лучше просто перенести все с нуля. У меня есть компонент, который, например, имеет представления поверх него, и карта отвечает на обычные события касания, а затем поля разрешают все остальное. Просто в принципе... - person sfratini; 19.01.2018
comment
...добавление полей с абсолютным позиционированием поверх карты. Не стесняйтесь пинговать меня в чате (на самом деле я им не пользовался), и я покажу вам, как мы это делаем. - person sfratini; 19.01.2018
comment
Это было самое первое, что мы протестировали. Сложность различных наложений карт довольно сложно описать небольшими сообщениями. Чтобы понять масштаб проблемы: на полный рефакторинг экрана карты уйдет около 2 месяцев команды из 5 человек. Это серьезно замедлит нашу скорость разработки. Поверх карты есть множество различных функций. - person XzKto; 19.01.2018
comment
Смотрите мой отредактированный ответ. Это еще один способ отправки событий представлениям ниже. Не стесняйтесь обращаться. - person sfratini; 19.01.2018
comment
Большое спасибо за этот пример!! Похоже, это работает с простыми тестовыми примерами. Мы проверим полную интеграцию карт в понедельник и опубликуем результаты здесь. В любом случае это очень полезно. - person XzKto; 19.01.2018
comment
На самом деле это не ответило на наш вопрос, но в целом было полезно, и мы сами близки к решению этой проблемы. - person XzKto; 25.01.2018
comment
@XzKto Вы нашли решение? Я думаю, что борюсь с той же проблемой. См. stackoverflow.com/questions/53152420/ - person suamikim; 05.11.2018