Отрешите Native Maps Mark, а не на Android, но работайте, как и ожидалось, на iOSAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Отрешите Native Maps Mark, а не на Android, но работайте, как и ожидалось, на iOS

Сообщение Anonymous »

Я использую реагирующие карты с кластеризацией на карте. При масштабировании маркеры отображаются с изображениями на основе жанров. Проблема в том, что маркеры не рендеринг на 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
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»