Anonymous
Отрешите Native Maps Mark, а не на Android, но работайте, как и ожидалось, на iOS
Сообщение
Anonymous » 15 сен 2025, 19:03
Я использую реагирующие карты с кластеризацией на карте. При масштабировании маркеры отображаются с изображениями на основе жанров. Проблема в том, что маркеры не рендеринг на Android, хотя они работают, как и ожидалось на iOS. Я попытался понижать версию 1.20.1 и обновить до последней версии, но проблема сохраняется. Я также пытался использовать форматы SVG, PNG и JPEG, но маркеры все еще не отображаются. Может ли кто -нибудь помочь мне решить эту проблему?
Код: Выделить всё
import React, {useRef, useState, useEffect, useMemo, useCallback} from 'react';
import {
View,
Text,
StyleSheet,
Dimensions,
Animated,
PanResponder,
LayoutChangeEvent,
ActivityIndicator,
Platform,
Image,
TouchableOpacity,
ScrollView,
ViewStyle,
TextStyleIOS,
StatusBar,
ImageBackground,
} from 'react-native';
import {offsetOverlappingCoordinates} from '../utils/offSetSameCoordinate';
import NetInfo from '@react-native-community/netinfo';
import MapView, {Marker, Region} from 'react-native-maps';
import HeaderUser from '../components/HeaderUser';
import EventCard from '../components/EventCard';
import {config} from '../constants/config';
import SearchBottomSheet, {
SearchBottomSheetRef,
} from '../components/SearchBottomSheet';
import {
useGetUserNearbyEventsQuery,
useGetEventByIdQuery,
} from '../services/api/eventApi';
import {useRoute, RouteProp, useNavigation} from '@react-navigation/native';
import {EnumDuration, IEvent, IEventArtist, IGetNearbyEventParams} from '../types.d';
import {getGenreImage, getGenreBackgroundImage} from '../utils/getGenresImage';
import {createClusters} from '../utils/mapScreen';
import {requestUserLocation} from '../utils/locationHelper';
import AppImage from '../components/BaseImage';
const {height, width} = Dimensions.get('window');
const STATUS_BAR_HEIGHT =
StatusBar.currentHeight || (Platform.OS === 'ios' ? 44 : 0);
const HEADER_HEIGHT = 80;
const SAFE_TOP_MARGIN = STATUS_BAR_HEIGHT + HEADER_HEIGHT - 70;
const SNAP_BOTTOM = height - 170;
const MAX_SHEET_HEIGHT = height {
const route = useRoute();
const {
eventId,
showSpecificEvent,
latitude: paramLatitude,
longitude: paramLongitude,
} = route.params || {};
const mapRef = useRef(null);
const scrollViewRef = useRef(null);
const scrollY = useRef(0);
const [locationFetched, setLocationFetched] = useState(false);
const bottomSheetHeight = useRef(0);
const isDraggingSheet = useRef(false);
const isScrolling = useRef(false);
const [deviceSize, setDeviceSize] = useState({width, height});
const [singleEventCardHeight, setSingleEventCardHeight] = useState(
Math.min(250, height * (height {
setIsInitialMarkerLoad(false);
}, 1000);
return () => clearTimeout(timer);
}, [apiEvents, specificEventData, mapIEventToEvent, showSpecificEvent]);
useEffect(() => {
if (error || specificEventError) {
console.error('Error fetching events:', error || specificEventError);
setShowNoResultsMessage(true);
}
}, [error, specificEventError]);
const panY = useRef(new Animated.Value(SNAP_BOTTOM)).current;
const [isSheetOpen, setIsSheetOpen] = useState(false);
const clusterArray = useMemo(() => {
if (showSpecificEvent) {
return [];
}
return createClusters(filteredEvents, currentZoomLevel);
}, [filteredEvents, currentZoomLevel, showSpecificEvent]);
const filteredClusters = useMemo(() => {
if (showSpecificEvent || !filtersApplied) {
return createClusters(events, currentZoomLevel);
}
return clusterArray;
}, [
events,
clusterArray,
filtersApplied,
currentZoomLevel,
showSpecificEvent,
]);
useEffect(() => {
if (showSpecificEvent) {
return;
}
if (viewMode === 'clusters') {
setVisibleEvents(filteredEvents);
} else if (activeClusterIndex !== null) {
const currentCluster = filteredClusters[activeClusterIndex];
if (currentCluster) {
setVisibleEvents(currentCluster.events);
}
}
}, [
filtersApplied,
filteredClusters,
filteredEvents,
viewMode,
activeClusterIndex,
showSpecificEvent,
]);
useEffect(() => {
if (filtersApplied && filteredEvents.length === 0 && !showSpecificEvent) {
setShowNoResultsMessage(true);
} else {
setShowNoResultsMessage(false);
}
}, [filtersApplied, filteredEvents, showSpecificEvent]);
const expandToFullScreen = () => {
Animated.spring(panY, {
toValue: TOP_CONSTRAINT,
useNativeDriver: false,
tension: 70,
friction: 12,
}).start(() => setIsSheetOpen(true));
};
const handleClusterPress = (clusterIndex: number) => {
if (showSpecificEvent) {
return;
}
setActiveClusterIndex(clusterIndex);
setViewMode('events');
if (isSheetOpen) {
closeBottomSheet();
setSelectedEventIndex(null);
}
const cluster = filteredClusters[clusterIndex];
if (mapRef.current) {
mapRef.current.animateToRegion(
{
latitude: cluster.coordinate.latitude,
longitude: cluster.coordinate.longitude,
latitudeDelta: 0.03,
longitudeDelta: 0.03,
},
1000,
);
}
setVisibleEvents(cluster.events);
if (cluster.events.length > 3) {
expandToFullScreen();
} else {
openBottomSheet();
}
};
const handleEventMarkerPress = (eventIndex: number) => {
setIsLoading(true);
setSelectedEventIndex(eventIndex);
const currentEvent = visibleEvents[eventIndex];
if (mapRef.current) {
mapRef.current.animateToRegion(
{
latitude: currentEvent.coordinate.latitude,
longitude: currentEvent.coordinate.longitude,
latitudeDelta: 0.001,
longitudeDelta: 0.001,
},
500,
);
}
const targetHeight = determineBottomSheetHeight();
Animated.spring(panY, {
toValue: targetHeight,
useNativeDriver: false,
tension: 70,
friction: 12,
}).start(() => setIsSheetOpen(true));
setTimeout(() => {
setIsLoading(false);
}, 250);
};
const handleCenterToUserLocation = async () => {
try {
setIsLoading(true);
const userRegion = await requestUserLocation();
setUserLocation(userRegion);
if (mapRef.current) {
mapRef.current.animateToRegion(
{
latitude: userRegion.latitude,
longitude: userRegion.longitude,
latitudeDelta: 0.0009,
longitudeDelta: 0.0009,
},
1000,
);
}
} catch (locationError) {
console.error('Failed to fetch user location:', locationError);
} finally {
setIsLoading(false);
}
};
const handleRegionChange = (region: Region) => {
if (showSpecificEvent) {
return;
}
setCurrentZoomLevel(region.latitudeDelta);
if (region.latitudeDelta > 0.05 && viewMode === 'events') {
setViewMode('clusters');
setVisibleEvents(filteredEvents);
setActiveClusterIndex(null);
if (isSheetOpen) {
closeBottomSheet();
setSelectedEventIndex(null);
}
setSelectedEventIndex(null);
} else if (region.latitudeDelta {
const distance = Math.sqrt(
Math.pow(region.latitude - cluster.coordinate.latitude, 2) +
Math.pow(region.longitude - cluster.coordinate.longitude, 2),
);
if (distance < minDistance) {
minDistance = distance;
closestClusterIndex = index;
}
});
if (closestClusterIndex !== -1 && minDistance < 0.02) {
setActiveClusterIndex(closestClusterIndex);
setViewMode('events');
if (isSheetOpen) {
closeBottomSheet();
setSelectedEventIndex(null);
}
const cluster = filteredClusters[closestClusterIndex];
setVisibleEvents(cluster.events);
// Don't automatically open or expand the bottom sheet on zoom
// This prevents the sheet from opening when zooming in
}
}
};
const handleScrollBegin = () => {
isScrolling.current = true;
};
const handleScrollEnd = () => {
isScrolling.current = false;
};
const handleScroll = (event: any) => {
scrollY.current = event.nativeEvent.contentOffset.y;
const eventsToShow = isSearchActive
? events.filter(event => {
const lowercaseQuery = searchQuery.toLowerCase();
return (
event.location.toLowerCase().includes(lowercaseQuery) ||
event.name.toLowerCase().includes(lowercaseQuery)
);
})
: filtersApplied
? filteredEvents
: viewMode === 'events'
? visibleEvents
: events;
if (
eventsToShow.length > 3 &&
isSheetOpen &&
selectedEventIndex === null &&
!showSpecificEvent
) {
expandToFullScreen();
}
};
const handleBottomSheetLayout = (event: LayoutChangeEvent) => {
bottomSheetHeight.current = event.nativeEvent.layout.height;
};
const panResponder = useRef(
PanResponder.create({
onMoveShouldSetPanResponder: (evt, gestureState) => {
const isSignificantVerticalGesture =
Math.abs(gestureState.dy) > 10 &&
Math.abs(gestureState.dy) > Math.abs(gestureState.dx);
if (!isSignificantVerticalGesture) {
return false;
}
const isDraggingHandle = evt.nativeEvent.locationY < 60;
const isAtTopOfScrollView = scrollY.current 0;
return isDraggingHandle || (isAtTopOfScrollView && isDraggingDown);
},
onPanResponderGrant: () => {
panY.setOffset(panY._value);
panY.setValue(0);
isDraggingSheet.current = true;
},
onPanResponderMove: (_, gestureState) => {
let newY = gestureState.dy;
const minHeight = determineBottomSheetHeight();
const maxHeight = SNAP_BOTTOM;
const currentPosition = panY._offset + newY;
if (currentPosition < minHeight) {
newY = minHeight - panY._offset;
} else if (currentPosition > maxHeight) {
newY = maxHeight - panY._offset;
}
panY.setValue(newY);
},
onPanResponderRelease: (_, gestureState) => {
panY.flattenOffset();
isDraggingSheet.current = false;
const currentPosition = panY._value;
const velocity = gestureState.vy;
const shouldOpen =
velocity < -0.3 ||
(velocity > -0.3 &&
velocity < 0.3 &&
currentPosition < SNAP_BOTTOM / 2);
const targetValue = shouldOpen
? determineBottomSheetHeight()
: SNAP_BOTTOM;
Animated.spring(panY, {
toValue: targetValue,
useNativeDriver: false,
tension: 70,
friction: 12,
}).start(() => {
setIsSheetOpen(shouldOpen);
});
},
onPanResponderTerminate: (_, _gestureState) => {
panY.flattenOffset();
isDraggingSheet.current = false;
const currentPosition = panY._value;
const shouldOpen = currentPosition < SNAP_BOTTOM / 2;
const targetValue = shouldOpen
? determineBottomSheetHeight()
: SNAP_BOTTOM;
Animated.spring(panY, {
toValue: targetValue,
useNativeDriver: false,
tension: 70,
friction: 12,
}).start(() => {
setIsSheetOpen(shouldOpen);
});
},
}),
).current;
const handleEventCardLayout = (event: LayoutChangeEvent) => {
const {height: cardHeight} = event.nativeEvent.layout;
const isSmallDevice = deviceSize.height {
if (filtersApplied && filteredEvents.length === 0) {
return;
}
if (showSpecificEvent) {
return;
}
setSelectedEventIndex(null);
const eventsToShow = isSearchActive
? events.filter(event => {
const lowercaseQuery = searchQuery.toLowerCase();
return (
event.location.toLowerCase().includes(lowercaseQuery) ||
event.name.toLowerCase().includes(lowercaseQuery)
);
})
: filtersApplied
? filteredEvents
: viewMode === 'events'
? visibleEvents
: events;
if (eventsToShow.length > 3) {
expandToFullScreen();
} else {
openBottomSheet();
}
};
const handleSearch = () => {
if (!searchQuery) {
setIsSearchActive(false);
}
searchBottomSheetRef.current?.open();
};
const handleSelectSearchResult = (result: string) => {
setSearchQuery(result);
setIsSearchActive(true);
let matchedEvents = 0;
if (result) {
const lowercaseResult = result.toLowerCase();
matchedEvents = events.filter(
event =>
event.location.toLowerCase().includes(lowercaseResult) ||
event.name.toLowerCase().includes(lowercaseResult),
).length;
}
setSearchResultsCount(matchedEvents);
if (matchedEvents > 0) {
setSelectedEventIndex(null);
if (matchedEvents > 3) {
expandToFullScreen();
} else {
openBottomSheet();
}
}
};
const handleMapReady = () => {
setMapReady(true); // Trigger image re-render
};
// Fallback image source
const defaultGenreImage = {uri: 'https://via.placeholder.com/66'};
const getSafeGenreImage = useCallback((genre: string) => {
const imageSource = getGenreImage(genre);
if (!imageSource || (typeof imageSource === 'object' && !imageSource.uri)) {
console.warn(`Invalid genre image for ${genre}, using default`);
return defaultGenreImage;
}
return imageSource;
}, []);
const getSafeGenreBackgroundImage = useCallback((genre: string) => {
const backgroundImage = getGenreBackgroundImage(genre);
if (
!backgroundImage ||
(typeof backgroundImage === 'object' && !backgroundImage.uri)
) {
console.warn(
`Invalid genre background image for ${genre}, using checkmap fallback`,
);
return require('../assets/checkmap.png'); // fallback to your original image
}
return backgroundImage;
}, []);
const currentEvent =
selectedEventIndex !== null && viewMode === 'events'
? visibleEvents[selectedEventIndex]
: null;
const visibleEventsCount = filteredEvents.length;
const isLoadingEvents = showSpecificEvent
? isFetchingSpecificEvent
: isFetchingEvents;
return (
{isLoading && !locationFetched && (
Getting your location...
)}
{mapReady &&
isConnected &&
viewMode === 'clusters' &&
!showSpecificEvent &&
filteredClusters.map((cluster, index) => (
(markerRefs.current[`cluster-${index}`] = ref)} // Add ref
coordinate={cluster.coordinate}
onPress={() => handleClusterPress(index)}
tracksViewChanges={isInitialMarkerLoad}>
{cluster.count}
))}
{mapReady &&
isConnected &&
(viewMode === 'events' || showSpecificEvent) &&
(() => {
const adjustedCoordinates =
offsetOverlappingCoordinates(visibleEvents);
return visibleEvents.map((event, index) => {
const isSelected = index === selectedEventIndex;
const isZoomedIn = currentZoomLevel
{showCallout ? (
{event.name}
{event.artist?.map((artist, artistIndex) => (
{artist.name}
))}
{event.venue?.map((venue, venueIndex) => (
{venue.name}
))}
) : (
{1}
)}
);
});
})()}
{
if (
event.nativeEvent.layout.height > 0 &&
doubleEventCardHeight === 520
) {
const isSmallDevice = deviceSize.height
{(() => {
const eventsToShow = showSpecificEvent
? events
: isSearchActive
? events.filter(event => {
const lowercaseQuery = searchQuery.toLowerCase();
return (
event.location.toLowerCase().includes(lowercaseQuery) ||
event.name.toLowerCase().includes(lowercaseQuery)
);
})
: filtersApplied
? filteredEvents
: viewMode === 'events'
? visibleEvents
: events;
if (eventsToShow.length === 0) {
return (
No events found
);
} else if (eventsToShow.length === 1) {
const singleEvent = eventsToShow[0];
return (
);
}
return eventsToShow.map((event, index) => (
));
})()}
)
) : null}
{!showSpecificEvent && (
)}
);
};
export default MapScreenUser;
Я стараюсь понизить версию до 1.20.1, а также попытаться перейти на последнее, но она не будет рендерингом.
Подробнее здесь:
https://stackoverflow.com/questions/797 ... ted-on-ios
1757952224
Anonymous
Я использую реагирующие карты с кластеризацией на карте. При масштабировании маркеры отображаются с изображениями на основе жанров. Проблема в том, что маркеры не рендеринг на Android, хотя они работают, как и ожидалось на iOS. Я попытался понижать версию 1.20.1 и обновить до последней версии, но проблема сохраняется. Я также пытался использовать форматы SVG, PNG и JPEG, но маркеры все еще не отображаются. Может ли кто -нибудь помочь мне решить эту проблему?[code]import React, {useRef, useState, useEffect, useMemo, useCallback} from 'react'; import { View, Text, StyleSheet, Dimensions, Animated, PanResponder, LayoutChangeEvent, ActivityIndicator, Platform, Image, TouchableOpacity, ScrollView, ViewStyle, TextStyleIOS, StatusBar, ImageBackground, } from 'react-native'; import {offsetOverlappingCoordinates} from '../utils/offSetSameCoordinate'; import NetInfo from '@react-native-community/netinfo'; import MapView, {Marker, Region} from 'react-native-maps'; import HeaderUser from '../components/HeaderUser'; import EventCard from '../components/EventCard'; import {config} from '../constants/config'; import SearchBottomSheet, { SearchBottomSheetRef, } from '../components/SearchBottomSheet'; import { useGetUserNearbyEventsQuery, useGetEventByIdQuery, } from '../services/api/eventApi'; import {useRoute, RouteProp, useNavigation} from '@react-navigation/native'; import {EnumDuration, IEvent, IEventArtist, IGetNearbyEventParams} from '../types.d'; import {getGenreImage, getGenreBackgroundImage} from '../utils/getGenresImage'; import {createClusters} from '../utils/mapScreen'; import {requestUserLocation} from '../utils/locationHelper'; import AppImage from '../components/BaseImage'; const {height, width} = Dimensions.get('window'); const STATUS_BAR_HEIGHT = StatusBar.currentHeight || (Platform.OS === 'ios' ? 44 : 0); const HEADER_HEIGHT = 80; const SAFE_TOP_MARGIN = STATUS_BAR_HEIGHT + HEADER_HEIGHT - 70; const SNAP_BOTTOM = height - 170; const MAX_SHEET_HEIGHT = height { const route = useRoute(); const { eventId, showSpecificEvent, latitude: paramLatitude, longitude: paramLongitude, } = route.params || {}; const mapRef = useRef(null); const scrollViewRef = useRef(null); const scrollY = useRef(0); const [locationFetched, setLocationFetched] = useState(false); const bottomSheetHeight = useRef(0); const isDraggingSheet = useRef(false); const isScrolling = useRef(false); const [deviceSize, setDeviceSize] = useState({width, height}); const [singleEventCardHeight, setSingleEventCardHeight] = useState( Math.min(250, height * (height { setIsInitialMarkerLoad(false); }, 1000); return () => clearTimeout(timer); }, [apiEvents, specificEventData, mapIEventToEvent, showSpecificEvent]); useEffect(() => { if (error || specificEventError) { console.error('Error fetching events:', error || specificEventError); setShowNoResultsMessage(true); } }, [error, specificEventError]); const panY = useRef(new Animated.Value(SNAP_BOTTOM)).current; const [isSheetOpen, setIsSheetOpen] = useState(false); const clusterArray = useMemo(() => { if (showSpecificEvent) { return []; } return createClusters(filteredEvents, currentZoomLevel); }, [filteredEvents, currentZoomLevel, showSpecificEvent]); const filteredClusters = useMemo(() => { if (showSpecificEvent || !filtersApplied) { return createClusters(events, currentZoomLevel); } return clusterArray; }, [ events, clusterArray, filtersApplied, currentZoomLevel, showSpecificEvent, ]); useEffect(() => { if (showSpecificEvent) { return; } if (viewMode === 'clusters') { setVisibleEvents(filteredEvents); } else if (activeClusterIndex !== null) { const currentCluster = filteredClusters[activeClusterIndex]; if (currentCluster) { setVisibleEvents(currentCluster.events); } } }, [ filtersApplied, filteredClusters, filteredEvents, viewMode, activeClusterIndex, showSpecificEvent, ]); useEffect(() => { if (filtersApplied && filteredEvents.length === 0 && !showSpecificEvent) { setShowNoResultsMessage(true); } else { setShowNoResultsMessage(false); } }, [filtersApplied, filteredEvents, showSpecificEvent]); const expandToFullScreen = () => { Animated.spring(panY, { toValue: TOP_CONSTRAINT, useNativeDriver: false, tension: 70, friction: 12, }).start(() => setIsSheetOpen(true)); }; const handleClusterPress = (clusterIndex: number) => { if (showSpecificEvent) { return; } setActiveClusterIndex(clusterIndex); setViewMode('events'); if (isSheetOpen) { closeBottomSheet(); setSelectedEventIndex(null); } const cluster = filteredClusters[clusterIndex]; if (mapRef.current) { mapRef.current.animateToRegion( { latitude: cluster.coordinate.latitude, longitude: cluster.coordinate.longitude, latitudeDelta: 0.03, longitudeDelta: 0.03, }, 1000, ); } setVisibleEvents(cluster.events); if (cluster.events.length > 3) { expandToFullScreen(); } else { openBottomSheet(); } }; const handleEventMarkerPress = (eventIndex: number) => { setIsLoading(true); setSelectedEventIndex(eventIndex); const currentEvent = visibleEvents[eventIndex]; if (mapRef.current) { mapRef.current.animateToRegion( { latitude: currentEvent.coordinate.latitude, longitude: currentEvent.coordinate.longitude, latitudeDelta: 0.001, longitudeDelta: 0.001, }, 500, ); } const targetHeight = determineBottomSheetHeight(); Animated.spring(panY, { toValue: targetHeight, useNativeDriver: false, tension: 70, friction: 12, }).start(() => setIsSheetOpen(true)); setTimeout(() => { setIsLoading(false); }, 250); }; const handleCenterToUserLocation = async () => { try { setIsLoading(true); const userRegion = await requestUserLocation(); setUserLocation(userRegion); if (mapRef.current) { mapRef.current.animateToRegion( { latitude: userRegion.latitude, longitude: userRegion.longitude, latitudeDelta: 0.0009, longitudeDelta: 0.0009, }, 1000, ); } } catch (locationError) { console.error('Failed to fetch user location:', locationError); } finally { setIsLoading(false); } }; const handleRegionChange = (region: Region) => { if (showSpecificEvent) { return; } setCurrentZoomLevel(region.latitudeDelta); if (region.latitudeDelta > 0.05 && viewMode === 'events') { setViewMode('clusters'); setVisibleEvents(filteredEvents); setActiveClusterIndex(null); if (isSheetOpen) { closeBottomSheet(); setSelectedEventIndex(null); } setSelectedEventIndex(null); } else if (region.latitudeDelta { const distance = Math.sqrt( Math.pow(region.latitude - cluster.coordinate.latitude, 2) + Math.pow(region.longitude - cluster.coordinate.longitude, 2), ); if (distance < minDistance) { minDistance = distance; closestClusterIndex = index; } }); if (closestClusterIndex !== -1 && minDistance < 0.02) { setActiveClusterIndex(closestClusterIndex); setViewMode('events'); if (isSheetOpen) { closeBottomSheet(); setSelectedEventIndex(null); } const cluster = filteredClusters[closestClusterIndex]; setVisibleEvents(cluster.events); // Don't automatically open or expand the bottom sheet on zoom // This prevents the sheet from opening when zooming in } } }; const handleScrollBegin = () => { isScrolling.current = true; }; const handleScrollEnd = () => { isScrolling.current = false; }; const handleScroll = (event: any) => { scrollY.current = event.nativeEvent.contentOffset.y; const eventsToShow = isSearchActive ? events.filter(event => { const lowercaseQuery = searchQuery.toLowerCase(); return ( event.location.toLowerCase().includes(lowercaseQuery) || event.name.toLowerCase().includes(lowercaseQuery) ); }) : filtersApplied ? filteredEvents : viewMode === 'events' ? visibleEvents : events; if ( eventsToShow.length > 3 && isSheetOpen && selectedEventIndex === null && !showSpecificEvent ) { expandToFullScreen(); } }; const handleBottomSheetLayout = (event: LayoutChangeEvent) => { bottomSheetHeight.current = event.nativeEvent.layout.height; }; const panResponder = useRef( PanResponder.create({ onMoveShouldSetPanResponder: (evt, gestureState) => { const isSignificantVerticalGesture = Math.abs(gestureState.dy) > 10 && Math.abs(gestureState.dy) > Math.abs(gestureState.dx); if (!isSignificantVerticalGesture) { return false; } const isDraggingHandle = evt.nativeEvent.locationY < 60; const isAtTopOfScrollView = scrollY.current 0; return isDraggingHandle || (isAtTopOfScrollView && isDraggingDown); }, onPanResponderGrant: () => { panY.setOffset(panY._value); panY.setValue(0); isDraggingSheet.current = true; }, onPanResponderMove: (_, gestureState) => { let newY = gestureState.dy; const minHeight = determineBottomSheetHeight(); const maxHeight = SNAP_BOTTOM; const currentPosition = panY._offset + newY; if (currentPosition < minHeight) { newY = minHeight - panY._offset; } else if (currentPosition > maxHeight) { newY = maxHeight - panY._offset; } panY.setValue(newY); }, onPanResponderRelease: (_, gestureState) => { panY.flattenOffset(); isDraggingSheet.current = false; const currentPosition = panY._value; const velocity = gestureState.vy; const shouldOpen = velocity < -0.3 || (velocity > -0.3 && velocity < 0.3 && currentPosition < SNAP_BOTTOM / 2); const targetValue = shouldOpen ? determineBottomSheetHeight() : SNAP_BOTTOM; Animated.spring(panY, { toValue: targetValue, useNativeDriver: false, tension: 70, friction: 12, }).start(() => { setIsSheetOpen(shouldOpen); }); }, onPanResponderTerminate: (_, _gestureState) => { panY.flattenOffset(); isDraggingSheet.current = false; const currentPosition = panY._value; const shouldOpen = currentPosition < SNAP_BOTTOM / 2; const targetValue = shouldOpen ? determineBottomSheetHeight() : SNAP_BOTTOM; Animated.spring(panY, { toValue: targetValue, useNativeDriver: false, tension: 70, friction: 12, }).start(() => { setIsSheetOpen(shouldOpen); }); }, }), ).current; const handleEventCardLayout = (event: LayoutChangeEvent) => { const {height: cardHeight} = event.nativeEvent.layout; const isSmallDevice = deviceSize.height { if (filtersApplied && filteredEvents.length === 0) { return; } if (showSpecificEvent) { return; } setSelectedEventIndex(null); const eventsToShow = isSearchActive ? events.filter(event => { const lowercaseQuery = searchQuery.toLowerCase(); return ( event.location.toLowerCase().includes(lowercaseQuery) || event.name.toLowerCase().includes(lowercaseQuery) ); }) : filtersApplied ? filteredEvents : viewMode === 'events' ? visibleEvents : events; if (eventsToShow.length > 3) { expandToFullScreen(); } else { openBottomSheet(); } }; const handleSearch = () => { if (!searchQuery) { setIsSearchActive(false); } searchBottomSheetRef.current?.open(); }; const handleSelectSearchResult = (result: string) => { setSearchQuery(result); setIsSearchActive(true); let matchedEvents = 0; if (result) { const lowercaseResult = result.toLowerCase(); matchedEvents = events.filter( event => event.location.toLowerCase().includes(lowercaseResult) || event.name.toLowerCase().includes(lowercaseResult), ).length; } setSearchResultsCount(matchedEvents); if (matchedEvents > 0) { setSelectedEventIndex(null); if (matchedEvents > 3) { expandToFullScreen(); } else { openBottomSheet(); } } }; const handleMapReady = () => { setMapReady(true); // Trigger image re-render }; // Fallback image source const defaultGenreImage = {uri: 'https://via.placeholder.com/66'}; const getSafeGenreImage = useCallback((genre: string) => { const imageSource = getGenreImage(genre); if (!imageSource || (typeof imageSource === 'object' && !imageSource.uri)) { console.warn(`Invalid genre image for ${genre}, using default`); return defaultGenreImage; } return imageSource; }, []); const getSafeGenreBackgroundImage = useCallback((genre: string) => { const backgroundImage = getGenreBackgroundImage(genre); if ( !backgroundImage || (typeof backgroundImage === 'object' && !backgroundImage.uri) ) { console.warn( `Invalid genre background image for ${genre}, using checkmap fallback`, ); return require('../assets/checkmap.png'); // fallback to your original image } return backgroundImage; }, []); const currentEvent = selectedEventIndex !== null && viewMode === 'events' ? visibleEvents[selectedEventIndex] : null; const visibleEventsCount = filteredEvents.length; const isLoadingEvents = showSpecificEvent ? isFetchingSpecificEvent : isFetchingEvents; return ( {isLoading && !locationFetched && ( Getting your location... )} {mapReady && isConnected && viewMode === 'clusters' && !showSpecificEvent && filteredClusters.map((cluster, index) => ( (markerRefs.current[`cluster-${index}`] = ref)} // Add ref coordinate={cluster.coordinate} onPress={() => handleClusterPress(index)} tracksViewChanges={isInitialMarkerLoad}> {cluster.count} ))} {mapReady && isConnected && (viewMode === 'events' || showSpecificEvent) && (() => { const adjustedCoordinates = offsetOverlappingCoordinates(visibleEvents); return visibleEvents.map((event, index) => { const isSelected = index === selectedEventIndex; const isZoomedIn = currentZoomLevel {showCallout ? ( {event.name} {event.artist?.map((artist, artistIndex) => ( {artist.name} ))} {event.venue?.map((venue, venueIndex) => ( {venue.name} ))} ) : ( {1} )} ); }); })()} { if ( event.nativeEvent.layout.height > 0 && doubleEventCardHeight === 520 ) { const isSmallDevice = deviceSize.height {(() => { const eventsToShow = showSpecificEvent ? events : isSearchActive ? events.filter(event => { const lowercaseQuery = searchQuery.toLowerCase(); return ( event.location.toLowerCase().includes(lowercaseQuery) || event.name.toLowerCase().includes(lowercaseQuery) ); }) : filtersApplied ? filteredEvents : viewMode === 'events' ? visibleEvents : events; if (eventsToShow.length === 0) { return ( No events found ); } else if (eventsToShow.length === 1) { const singleEvent = eventsToShow[0]; return ( ); } return eventsToShow.map((event, index) => ( )); })()} ) ) : null} {!showSpecificEvent && ( )} ); }; export default MapScreenUser; [/code] Я стараюсь понизить версию до 1.20.1, а также попытаться перейти на последнее, но она не будет рендерингом. Подробнее здесь: [url]https://stackoverflow.com/questions/79765370/react-native-maps-marker-not-render-on-android-but-work-as-expected-on-ios[/url]