Bladeren bron

android zoom fix

Viktoriia 2 maanden geleden
bovenliggende
commit
9d36817a1c
1 gewijzigde bestanden met toevoegingen van 173 en 15 verwijderingen
  1. 173 15
      src/screens/InAppScreens/MapScreen/index.tsx

+ 173 - 15
src/screens/InAppScreens/MapScreen/index.tsx

@@ -437,6 +437,9 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
   const [center, setCenter] = useState<number[] | null>(null);
   const [isZooming, setIsZooming] = useState(true);
   const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
+  const [renderCamera, setRenderCamera] = useState(Platform.OS === 'ios');
+  const isAnimatingRef = useRef(false);
+  const animationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
 
   const [markerCoords, setMarkerCoords] = useState<any>(null);
   const [refreshInterval, setRefreshInterval] = useState(0);
@@ -766,10 +769,11 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
       setMarkerCoords([route.params.lon, route.params.lat]);
       const timeoutId = setTimeout(() => {
         if (cameraRef.current) {
-          cameraRef.current.setCamera({
+          cameraController.setCamera({
             centerCoordinate: [route.params?.lon, route.params?.lat],
             zoomLevel: 15,
-            animationDuration: 800
+            animationDuration: 800,
+            animationMode: 'flyTo'
           });
         } else {
           console.warn('Camera ref is not available.');
@@ -885,6 +889,149 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
   const cameraRef = useRef<MapLibreRN.CameraRef>(null);
   const shapeSourceRef = useRef<MapLibreRN.ShapeSourceRef>(null);
 
+  const cameraController = {
+    setCamera: useCallback((config: any) => {
+      isAnimatingRef.current = true;
+
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+
+        requestAnimationFrame(() => {
+          cameraRef.current?.setCamera(config);
+        });
+
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+            setRenderCamera(false);
+          },
+          (config.animationDuration || 1000) + 200
+        );
+      } else {
+        cameraRef.current?.setCamera(config);
+
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+          },
+          (config.animationDuration || 1000) + 100
+        );
+      }
+    }, []),
+
+    fitBounds: useCallback((ne: number[], sw: number[], padding: number[], duration: number) => {
+      isAnimatingRef.current = true;
+
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+
+        requestAnimationFrame(() => {
+          cameraRef.current?.fitBounds(ne, sw, padding, duration);
+        });
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+          setRenderCamera(false);
+        }, duration + 200);
+      } else {
+        cameraRef.current?.fitBounds(ne, sw, padding, duration);
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+        }, duration + 100);
+      }
+    }, []),
+
+    flyTo: useCallback((coordinates: number[], duration: number = 1000) => {
+      isAnimatingRef.current = true;
+
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+
+        requestAnimationFrame(() => {
+          cameraRef.current?.flyTo(coordinates, duration);
+        });
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+          setRenderCamera(false);
+        }, duration + 200);
+      } else {
+        cameraRef.current?.flyTo(coordinates, duration);
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+        }, duration + 100);
+      }
+    }, []),
+
+    moveTo: useCallback((coordinates: number[], duration: number = 0) => {
+      isAnimatingRef.current = true;
+
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+
+        requestAnimationFrame(() => {
+          cameraRef.current?.moveTo(coordinates, duration);
+        });
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+          setRenderCamera(false);
+        }, duration + 200);
+      } else {
+        cameraRef.current?.moveTo(coordinates, duration);
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+        }, duration + 100);
+      }
+    }, []),
+
+    zoomTo: useCallback((zoomLevel: number, duration: number = 1000) => {
+      isAnimatingRef.current = true;
+
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+
+        requestAnimationFrame(() => {
+          cameraRef.current?.zoomTo(zoomLevel, duration);
+        });
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+          setRenderCamera(false);
+        }, duration + 200);
+      } else {
+        cameraRef.current?.zoomTo(zoomLevel, duration);
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+        }, duration + 100);
+      }
+    }, [])
+  };
+
   useEffect(() => {
     if (userInfo) {
       setUserInfoData(JSON.parse(userInfo));
@@ -933,10 +1080,11 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
     if (initialRegion && !route.params?.id) {
       const timeoutId = setTimeout(() => {
         if (cameraRef.current) {
-          cameraRef.current.setCamera({
+          cameraController.setCamera({
             centerCoordinate: [initialRegion.longitude, initialRegion.latitude],
             zoomLevel: Math.log2(360 / initialRegion.latitudeDelta),
-            animationDuration: 500
+            animationDuration: 500,
+            animationMode: 'flyTo'
           });
         } else {
           console.warn('Camera ref is not available.');
@@ -948,7 +1096,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
   }, [initialRegion]);
 
   const handleMapChange = async () => {
-    if (!mapRef.current) return;
+    if (!mapRef.current || isAnimatingRef.current) return;
     if (hideTimer.current) clearTimeout(hideTimer.current);
 
     setIsZooming(true);
@@ -969,6 +1117,14 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
     });
   };
 
+  useEffect(() => {
+    return () => {
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+    };
+  }, []);
+
   const onMapPress = async (event: any) => {
     if (!mapRef.current) return;
     if (selectedMarker || selectedUser) {
@@ -1019,7 +1175,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
             const region = regionsList.data.find((region) => region.id === +foundRegion);
             if (region) {
               const bounds = turf.bbox(region.bbox);
-              cameraRef.current?.fitBounds(
+              cameraController.fitBounds(
                 [bounds[2], bounds[3]],
                 [bounds[0], bounds[1]],
                 [10, 10, 50, 10],
@@ -1042,7 +1198,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
             const region = countriesList.data.find((region) => region.id === +foundRegion);
             if (region) {
               const bounds = turf.bbox(region.bbox);
-              cameraRef.current?.fitBounds(
+              cameraController.fitBounds(
                 [bounds[2], bounds[3]],
                 [bounds[0], bounds[1]],
                 [10, 10, 50, 10],
@@ -1065,7 +1221,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
             const region = dareList.data.find((region) => region.id === +foundRegion);
             if (region) {
               const bounds = turf.bbox(region.bbox);
-              cameraRef.current?.fitBounds(
+              cameraController.fitBounds(
                 [bounds[2], bounds[3]],
                 [bounds[0], bounds[1]],
                 [10, 10, 50, 10],
@@ -1148,7 +1304,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
       setLocation(currentLocation.coords);
 
       if (currentLocation.coords) {
-        cameraRef.current?.flyTo(
+        cameraController.flyTo(
           [currentLocation.coords.longitude, currentLocation.coords.latitude],
           1000
         );
@@ -1254,7 +1410,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
           const region = regionsList.data.find((region) => region.id === +id);
           if (region) {
             const bounds = turf.bbox(region.bbox);
-            cameraRef.current?.fitBounds(
+            cameraController.fitBounds(
               [bounds[2], bounds[3]],
               [bounds[0], bounds[1]],
               [10, 10, 50, 10],
@@ -1278,7 +1434,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
           const region = countriesList.data.find((region) => region.id === +id);
           if (region) {
             const bounds = turf.bbox(region.bbox);
-            cameraRef.current?.fitBounds(
+            cameraController.fitBounds(
               [bounds[2], bounds[3]],
               [bounds[0], bounds[1]],
               [10, 10, 50, 10],
@@ -1302,7 +1458,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
           const region = dareList.data.find((region) => region.id === +id);
           if (region) {
             const bounds = turf.bbox(region.bbox);
-            cameraRef.current?.fitBounds(
+            cameraController.fitBounds(
               [bounds[2], bounds[3]],
               [bounds[0], bounds[1]],
               [10, 10, 50, 10],
@@ -1694,7 +1850,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
                 );
                 const newZoom = zoom ?? 2;
 
-                cameraRef.current?.setCamera({
+                cameraController.setCamera({
                   centerCoordinate: clusterCoordinates,
                   zoomLevel: newZoom,
                   animationDuration: 500,
@@ -1812,7 +1968,9 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
         {selectedMarker && (
           <MarkerItem marker={selectedMarker} toggleSeries={toggleSeries} token={token} />
         )}
-        {Platform.OS === 'ios' && <MapLibreRN.Camera ref={cameraRef} />}
+        {(renderCamera || Platform.OS === 'ios') && (
+          <MapLibreRN.Camera ref={cameraRef} followUserLocation={undefined} animationMode="flyTo" />
+        )}
         {location && (
           <MapLibreRN.UserLocation
             animated={true}
@@ -1821,7 +1979,7 @@ const MapScreen: any = ({ navigation, route }: { navigation: any; route: any })
               const currentZoom = await mapRef.current?.getZoom();
               const newZoom = (currentZoom || 0) + 2;
 
-              cameraRef.current?.setCamera({
+              cameraController.setCamera({
                 centerCoordinate: [location.longitude, location.latitude],
                 zoomLevel: newZoom,
                 animationDuration: 500,