React Native Mapbox-gl 因 React-navigation 崩溃

K10*_*000 5 android mapbox-gl react-native react-navigation

我有个问题。当我显示地图并@rnmapbox/maps想要在屏幕中导航时,应用程序冻结然后崩溃。<MapboxGL.MapView>我很确定这是一个 rnmapbox 问题,因为当我删除和之间的代码时<MapboxGL.MapView/>,导航工作正常。

我使用@react-navigation/native@react-navigation/native-stack 注意此问题不会在 iOS 上附加,仅在 Android 上附加。

问题记录: https: //vimeo.com/723749736

这是我的代码:

应用程序.js

import React from 'react';
import MapScreen from './src/screens/MapScreen';
import PlaceDetailsScreen from './src/screens/PlaceDetailsScreen';
import VideoPlayerScreen from './src/screens/VideoPlayerScreen';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import {NavigationContainer} from '@react-navigation/native';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import {GestureHandlerRootView} from 'react-native-gesture-handler';

function App() {
  const Stack = createNativeStackNavigator();
  return (
    <SafeAreaProvider>
      <GestureHandlerRootView style={{flex: 1}}>
        <NavigationContainer>
          <Stack.Navigator>
            <Stack.Screen
              name="Map"
              component={MapScreen}
              options={{headerShown: false}}
            />
            <Stack.Group>
              <Stack.Screen name="Details" component={PlaceDetailsScreen} />
              <Stack.Screen
                name="VideoPlayer"
                component={VideoPlayerScreen}
                options={{headerShown: false}}
              />
            </Stack.Group>
          </Stack.Navigator>
        </NavigationContainer>
      </GestureHandlerRootView>
    </SafeAreaProvider>
  );
}

export default App;
Run Code Online (Sandbox Code Playgroud)

地图屏幕.js

import React, {useState, useRef, useMemo, useCallback, useEffect} from 'react';
import {View, Text, PermissionsAndroid, Platform} from 'react-native';
import MapboxGL from '@rnmapbox/maps';
import BottomSheet, {BottomSheetScrollView} from '@gorhom/bottom-sheet';
import Styles from '../../Styles';
import PlaceBtn from '../components/PlaceBtn/PlaceBtn';
import IconPin from './../assets/icons/icon-locationPin.svg';
MapboxGL.setAccessToken(
  'XXXXXXXXXXXXXXXXXXXXXXXXXXX',
);

function MapScreen({navigation}) {
  const [hasGeolocPermission, setHasGeolocPermission] = useState(false);
  const [currentRegion, setCurrentRegion] = useState([4.824, 45.76]); //longitude, latitude
  const [userLocation, setUserLocation] = useState();
  const [nearestPoints, setNearestPoints] = useState([]);
  const markers = require('../data/markers.json');
  const route = require('../data/route.json');
  const routeLine = {
    type: 'FeatureCollection',
    features: [
      {
        type: 'Feature',
        properties: {},
        geometry: {
          type: 'LineString',
          coordinates: route.points,
        },
      },
    ],
  };

  const bottomSheetRef = useRef(null);
  const snapPoints = useMemo(() => ['13%', '75%', '100%'], []);

  const handleSheetChanges = useCallback(index => {
    console.log('handleSheetChanges', index);
  }, []);

  const requestLocationPermission = async () => {
    if (Platform.OS === 'android') {
      try {
        const granted = await PermissionsAndroid.request(
          PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
        );
        if (granted === PermissionsAndroid.RESULTS.GRANTED) {
          console.log('location uses is granted');
          setHasGeolocPermission(true);
        } else {
          console.log(granted);
          console.log('location access denied');
        }
      } catch (error) {
        console.warn('error while request location : ', error);
      }
    }
  };

  useEffect(() => {
    requestLocationPermission();
  }, []);
  return (
    <View style={Styles.container}>
      <MapboxGL.MapView style={Styles.map} scaleBarEnabled={false}>
        <MapboxGL.UserLocation
          animated
          showsUserHeadingIndicator
          minDisplacement={1}
          onUpdate={position => {
            console.log('position : ', position);
          }}
        />
        <MapboxGL.Camera centerCoordinate={currentRegion} zoomLevel={14} />
        {markers.map((marker, index) => {
          if (marker.category === 'introduction') {
            console.log('intro');
          } else {
            return (
              <MapboxGL.PointAnnotation
                key={index}
                id={marker.id + ''}
                coordinate={[marker.longitude, marker.latitude]}>
                <IconPin width={35} height={35} fill={'#00c0aa'} />
              </MapboxGL.PointAnnotation>
            );
          }
        })}
        <MapboxGL.ShapeSource id="line1" shape={routeLine}>
          <MapboxGL.LineLayer
            id="linelayer1"
            style={{lineColor: 'red', lineWidth: 5}}
          />
        </MapboxGL.ShapeSource>
      </MapboxGL.MapView>
      <BottomSheet
        ref={bottomSheetRef}
        handleIndicatorStyle={Styles.handleIndicator}
        index={0}
        snapPoints={snapPoints}
        onChange={handleSheetChanges}>
        <View style={Styles.bottomSheetContent}>
          <Text style={Styles.bottomSheetTitle}>{route.name}</Text>
          <BottomSheetScrollView>
            {markers.map((place, index) => {
              return (
                <PlaceBtn
                  place={place}
                  navigation={navigation}
                  //isNear={nearestPoints.includes(place.id)}
                />
              );
            })}
          </BottomSheetScrollView>
        </View>
      </BottomSheet>
    </View>
  );
}

export default MapScreen;
Run Code Online (Sandbox Code Playgroud)

PlaceDetailsS​​creen.js

import React from 'react';
import {View, Text, TouchableOpacity} from 'react-native';

function PlaceDetailsScreen({navigation}) {
  return (
    <>
      <TouchableOpacity
        style={{backgroundColor: '#00FF00'}}
        onPress={() => navigation.navigate('Map')}>
        <Text>Go to MAP</Text>
      </TouchableOpacity>
      <TouchableOpacity
        style={{backgroundColor: '#00FF00'}}
        onPress={() => navigation.navigate('VideoPlayer')}>
        <Text>Go to Video Player</Text>
      </TouchableOpacity>
    </>
  );
}
```
Run Code Online (Sandbox Code Playgroud)

小智 0

我有同样的问题。就我而言,我有一个在所有屏幕上持续存在的模式,当用户像在 YouTube 中一样向下滑动时,该模式会缩小。在模式内初始化地图后,每当我尝试更改屏幕时,我的应用程序都会首先冻结然后崩溃。

我的解决方案是仅在模态展开时渲染地图。所以我做了一个条件渲染。检查模态是否收缩。如果缩小,则渲染地图,否则不渲染。因此我的导航工作没有任何问题。

这是我的情况,这就是我解决它的方法:

 // I use reduxjs toolkit.
 // Since this modal is gonna be persistent through all screens
 // It's best to store translateY value in redux.
 const Modal = useAppSelector((state) => state.Modal);
 const translateY = useSharedValue(Modal.translateY);
 
 // I watch this variable with an useEffect hook to dynamically update redux value
 const [translateYState, setTranslateYState] = useState(translateY.value);

 useEffect(() => {
    dispatch(setTranslateY(translateYState));
  }, [translateYState]);

 // translateYState's value is dynamically updating by a pan gesture detector
 // translateYState value to be 0 means modal is expanded and user is using the modal
 return (
    <>
      {translateYState==0 && (
        <MapboxGL.MapView style={styles.map}></MapboxGL.MapView>
      )} 
    </>
   )
Run Code Online (Sandbox Code Playgroud)

当标题为“Les Sens de Lyon”的模态展开时,您可以取消渲染地图。如果您担心地图数据,您可以存储地图数据,例如 redux 中标记的所有位置以使其持久化,但如果您的应用程序是单页应用程序,那么这应该不是问题,否则您可以使用 redux。