英文:
Strange behaviour with mapView in CreateForm
问题
我今天遇到了与React Native相关的问题,具体是我遇到的奇怪行为。问题与地图(Map)有关。当我点击地图上的某个位置并设置一个标记时,它可以正常工作。但是当我想在其他地方放置标记时,它却不起作用。当我保存标记位置等信息并返回时,地图显示的是之前的图像,而不是带有标记的图像。下面是我发送的代码:
import React, { useEffect, useLayoutEffect, useState } from "react";
import {
launchImageLibraryAsync,
useMediaLibraryPermissions,
} from "expo-image-picker";
import * as Location from "expo-location";
import {
Alert,
Dimensions,
Image,
Pressable,
ScrollView,
Text,
TextInput,
View,
} from "react-native";
import MapView, { Marker } from "react-native-maps";
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
import IonIcons from "@expo/vector-icons/Ionicons";
import DateTimePicker from "@react-native-community/datetimepicker";
import { useIsFocused } from "@react-navigation/native";
const CreateForm = ({ navigation, route }) => {
const [isOpened, setIsOpened] = useState(false);
const [isEndOpened, setIsEndOpened] = useState(false);
const [date, setDate] = useState(new Date());
const [dateTitle, setDateTitle] = useState(null);
const [endDate, setEndDate] = useState(new Date());
const [endDateTitle, setEndDateTitle] = useState(null);
const [finalImages, setFinalImages] = useState([]);
const [currentLocation, setCurrentLocation] = useState(null);
const [markerCoords, setMarkerCoords] = useState(null);
const isFocused = useIsFocused();
useEffect(() => {
if (route.params && isFocused) {
setCurrentLocation(route.params.mapLayout);
setMarkerCoords(route.params.markerCoords);
}
}, [route, isFocused]);
const getLocationPermission = async () => {
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") {
setErrorMsg("Permission to access location was denied");
return;
}
let location = await Location.getCurrentPositionAsync();
console.log(location);
const locationObject = {
latitude: location.coords.latitude,
longitude: location.coords.longitude,
latitudeDelta: 0.0043,
longitudeDelta: 0.0034,
};
setCurrentLocation(locationObject);
};
const [status, requestPermission] = useMediaLibraryPermissions();
useLayoutEffect(() => {
navigation.setOptions({
title: "New Travel story",
headerRight: () => {},
});
}, []);
const openModal = () => {
setIsOpened(true);
};
const endModalOpen = () => {
setIsEndOpened(true);
};
const selectImages = async () => {
if (status.granted) {
const imageLibrary = await launchImageLibraryAsync({
allowsMultipleSelection: true,
});
if (imageLibrary.assets === null) {
setFinalImages([]);
return;
}
const allImages = [...finalImages, ...imageLibrary.assets];
if (allImages.length > 15) {
Alert.alert(
"Amount of pictures exceeded !",
"You are able only to add 15 pictures, in order not letting the app to break up. If you'd like to change all Images, click the button and choose again."
);
setFinalImages((prev) => {
const maxAmount = prev.slice(0, 15);
return [...maxAmount];
});
return;
}
setFinalImages((prev) => {
return [...prev, ...imageLibrary.assets];
});
} else {
await requestPermission();
}
};
const navigateToMapSelect = () => {
navigation.navigate("MapSelect", {
coords: currentLocation,
marker: markerCoords ? markerCoords : null,
});
};
return (
<ScrollView contentContainerStyle={{ padding: 16 }}>
<Text style={{ textAlign: "center", fontSize: 24, fontWeight: "500" }}>
Prepend a new Travel story{" "}
<IonIcons name="airplane-sharp" style={{ fontSize: 16 }} />
</Text>
<Text style={{ textAlign: "center", fontWeight: "300" }}>
And save the memories forever{" "}
<IonIcons name="infinite-sharp" style={{ fontSize: 24 }} />
</Text>
<View style={{ padding: 5 }}>
<View>
<Text>Place Name:</Text>
<TextInput
style={{
backgroundColor: "black",
padding: 5,
borderRadius: 5,
color: "white",
}}
placeholder="Type the name of the travel-place"
placeholderTextColor="gray"
/>
</View>
<View>
<Text>Description:</Text>
<TextInput
multiline
placeholder="Type the description"
style={{
backgroundColor: "black",
padding: 5,
borderRadius: 5,
color: "white",
}}
placeholderTextColor="gray"
/>
</View>
<View style={{ gap: 6, padding: 5, justifyContent: "space-between" }}>
<View>
<Text>Travel start:{dateTitle}</Text>
<Pressable
style={{
backgroundColor: "black",
borderRadius: 4,
padding: 6,
}}
android_ripple={{ color: "gray" }}
onPress={openModal}
>
<Text style={{ color: "white" }}>Select time</Text>
</Pressable>
{isOpened && (
<DateTimePicker
value={date ? date : new Date()}
onChange={(e) => {
setDate(new Date(e.nativeEvent.timestamp));
console.log(new Date(e.nativeEvent.timestamp));
setDateTitle(new Date(e.nativeEvent.timestamp).toUTCString());
setIsOpened(false);
}}
/>
)}
</View>
<View>
<Text>Travel end:{endDateTitle}</Text>
<Pressable
style={{ backgroundColor: "black", borderRadius: 4, padding: 6 }}
android_ripple={{ color: "gray" }}
onPress={endModalOpen}
>
<Text style={{ color: "white" }}>Select time</Text>
</Pressable>
{isEndOpened && (
<DateTimePicker
value={endDate ? endDate : new Date()}
onChange={(e) => {
setEndDate(new Date(e.nativeEvent.timestamp));
console.log(new Date(e.nativeEvent.timestamp));
setEndDateTitle(
new Date(e.nativeEvent.timestamp).toUTCString()
);
setIsEndOpened(false);
}}
/>
)}
</View>
</View>
<View>
<Pressable
style={{
backgroundColor: "black",
borderRadius: 4,
padding: 6,
margin: 12,
}}
android_ripple={{ color: "gray" }}
onPress={selectImages}
>
<Text style={{ color: "white" }}>
Select Images <MaterialCommunityIcons name="camera" />
</Text>
</Pressable>
</View>
{finalImages.length === 0 && (
<Text style={{ textAlign: "center" }}>
You haven't picked any image yet 😥
</Text>
)}
{finalImages.length > 0 && (
<>
<Text
style={{
fontWeight: "600",
textAlign: "center",
verticalAlign: "middle",
margin: 4,
}}
>
You have picked already {finalImages.length} pictures 😊
</Text>
<View
style={{
gap: 6,
flexWrap: "wrap",
flexDirection: "row",
justifyContent: "center",
}}
>
{finalImages.map((image, index) => (
<Image
key={index}
source={{ uri: image.uri }}
style={{
width: 50,
height: 50,
objectFit: "cover",
margin: 5,
}}
/>
))}
</View>
</>
)}
<View>
<Text style={{ fontWeight: "600", padding: 6, textAlign: "center" }}>
Choose the place on map that you visited:
</Text>
<MapView
scrollEnabled={false}
zoomEnabled={false}
initialRegion={currentLocation}
style={{
width: "100%",
height: Dimensions.get("window").height / 3,
}}
>
{markerCoords && <Marker coordinate={markerCoords} />}
</MapView>
<View
style={{
flexDirection: "row",
justifyContent: "space-around",
gap: 6,
}}
>
<Pressable
onPress={getLocationPermission}
android_ripple={{ color: "gray" }}
style={{
padding: 5,
margin: 5,
backgroundColor: "black",
alignItems: "center",
borderRadius: 5,
}}
>
<Text style={{ color: "white" }}>
Share Your Location{" "}
<IonIcons name="location" style={{ fontSize: 16 }} />
</Text>
</Pressable>
<Pressable
onPress={navigateToMapSelect}
android_ripple={{ color: "gray" }}
style={{
padding: 5,
margin: 5,
backgroundColor: "black",
alignItems: "center",
borderRadius: 5,
}}
>
<Text style={{ color: "white" }}>
Select on Map <IonIcons name="map" style={{ fontSize: 16 }} />
</Text>
</Pressable>
</View>
</View>
<Pressable
style={{ backgroundColor: "black", padding: 6, borderRadius: 4 }}
onPress={() => {
console.log(route.params);
}}
>
<Text style={{ color: "white", textAlign: "center" }}>Submit</Text>
</Pressable>
</View>
</ScrollView>
);
};
export default CreateForm;
import React, { useEffect, useState } from "react";
import { Pressable, Text, View } from "react-native";
import MapView, { Marker } from "react-native-maps";
import IonIcons from "@expo/vector-icons/Ionicons";
const MapSelect = ({ route, navigation }) => {
const [markerCoords, setMarkerCoords] = useState(null);
const [newMapLayout, setNewMapLayout] = useState(null);
const coordsForMap = route.params.coords;
const existingMarkerCoords = route.params.marker;
const selectPlaceOnMap = (e) => {
const coords = e.nativeEvent.coordinate;
const newMapsCoords = {
latitude: coords.latitude,
longitude: coords.longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
};
setNewMapLayout(newMapsCoords);
setMarkerCoords(coords);
console.log(newMapsCoords);
console.log(coords);
};
const saveMarker = () => {
navigation.navigate("StackScreen", {
mapLayout: newMapLayout,
markerCoords: markerCoords,
});
};
useEffect(() => {
if (existingMarkerCoords) {
setMarkerCoords(existingMarkerCoords);
}
}, [existingMarkerCoords]);
useEffect(() => {
navigation.setOptions({
headerRight: () => (
<Pressable onPress={saveMarker}>
<Text style={{ color: "white" }}>
Save <IonIcons name="save-sharp" />
</Text>
</Pressable>
),
});
}, [saveMarker]); // Listen to changes in newMapLayout and markerCoords
return (
<View>
<MapView
initialRegion={coordsForMap}
style={{ width: "100%", height: "100%" }}
onPress={selectPlaceOnMap}
>
{markerCoords && <Marker coordinate={markerCoords} />}
</MapView>
</View>
);
};
export default MapSelect;
我尽力了,但实际上我的尝试没有成功。所以我期望在保存标记后,MapView会显示带有标记的地点。
英文:
i come today with issue related to react-native and namely the strange behaviour i encountered. So, the issue is sorely connected with Map. When I click to select on Map a place and set a marker it does it. But when i want to place the marker somewhere else and i do it. When I save the marker position etc. and come back, the previous image of the map is displayed and not the one with marker. Below I've sent the code:
import React, { useEffect, useLayoutEffect, useState } from "react";
import {
launchImageLibraryAsync,
useMediaLibraryPermissions,
} from "expo-image-picker";
import * as Location from "expo-location";
import {
Alert,
Dimensions,
Image,
Pressable,
ScrollView,
Text,
TextInput,
View,
} from "react-native";
import MapView, { Marker } from "react-native-maps";
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
import IonIcons from "@expo/vector-icons/Ionicons";
import DateTimePicker from "@react-native-community/datetimepicker";
import { useIsFocused } from "@react-navigation/native";
const CreateForm = ({ navigation, route }) => {
const [isOpened, setIsOpened] = useState(false);
const [isEndOpened, setIsEndOpened] = useState(false);
const [date, setDate] = useState(new Date());
const [dateTitle, setDateTitle] = useState(null);
const [endDate, setEndDate] = useState(new Date());
const [endDateTitle, setEndDateTitle] = useState(null);
const [finalImages, setFinalImages] = useState([]);
const [currentLocation, setCurrentLocation] = useState(null);
const [markerCoords, setMarkerCoords] = useState(null);
const isFocused = useIsFocused();
useEffect(() => {
if (route.params && isFocused) {
setCurrentLocation(route.params.mapLayout);
setMarkerCoords(route.params.markerCoords);
}
}, [route, isFocused]);
const getLocationPermission = async () => {
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") {
setErrorMsg("Permission to access location was denied");
return;
}
let location = await Location.getCurrentPositionAsync();
console.log(location);
const locationObject = {
latitude: location.coords.latitude,
longitude: location.coords.longitude,
latitudeDelta: 0.0043,
longitudeDelta: 0.0034,
};
setCurrentLocation(locationObject);
};
const [status, requestPermission] = useMediaLibraryPermissions();
useLayoutEffect(() => {
navigation.setOptions({
title: "New Travel story",
headerRight: () => {},
});
}, []);
const openModal = () => {
setIsOpened(true);
};
const endModalOpen = () => {
setIsEndOpened(true);
};
const selectImages = async () => {
if (status.granted) {
const imageLibrary = await launchImageLibraryAsync({
allowsMultipleSelection: true,
});
if (imageLibrary.assets === null) {
setFinalImages([]);
return;
}
const allImages = [...finalImages, ...imageLibrary.assets];
if (allImages.length > 15) {
Alert.alert(
"Amount of pictures exceeded !",
"You are able only to add 15 pictures, in order not letting the app to break up. If you'd like to change all Images, click the button and choose again."
);
setFinalImages((prev) => {
const maxAmount = prev.slice(0, 15);
return [...maxAmount];
});
return;
}
setFinalImages((prev) => {
return [...prev, ...imageLibrary.assets];
});
} else {
await requestPermission();
}
};
const navigateToMapSelect = () => {
navigation.navigate("MapSelect", {
coords: currentLocation,
marker: markerCoords ? markerCoords : null,
});
};
return (
<ScrollView contentContainerStyle={{ padding: 16 }}>
<Text style={{ textAlign: "center", fontSize: 24, fontWeight: "500" }}>
Prepend a new Travel story{" "}
<IonIcons name="airplane-sharp" style={{ fontSize: 16 }} />
</Text>
<Text style={{ textAlign: "center", fontWeight: "300" }}>
And save the memories forever{" "}
<IonIcons name="infinite-sharp" style={{ fontSize: 24 }} />
</Text>
<View style={{ padding: 5 }}>
<View>
<Text>Place Name:</Text>
<TextInput
style={{
backgroundColor: "black",
padding: 5,
borderRadius: 5,
color: "white",
}}
placeholder="Type the name of the travel-place"
placeholderTextColor="gray"
/>
</View>
<View>
<Text>Description:</Text>
<TextInput
multiline
placeholder="Type the description"
style={{
backgroundColor: "black",
padding: 5,
borderRadius: 5,
color: "white",
}}
placeholderTextColor="gray"
/>
</View>
<View style={{ gap: 6, padding: 5, justifyContent: "space-between" }}>
<View>
<Text>Travel start:{dateTitle}</Text>
<Pressable
style={{
backgroundColor: "black",
borderRadius: 4,
padding: 6,
}}
android_ripple={{ color: "gray" }}
onPress={openModal}
>
<Text style={{ color: "white" }}>Select time</Text>
</Pressable>
{isOpened && (
<DateTimePicker
value={date ? date : new Date()}
onChange={(e) => {
setDate(new Date(e.nativeEvent.timestamp));
console.log(new Date(e.nativeEvent.timestamp));
setDateTitle(new Date(e.nativeEvent.timestamp).toUTCString());
setIsOpened(false);
}}
/>
)}
</View>
<View>
<Text>Travel end:{endDateTitle}</Text>
<Pressable
style={{ backgroundColor: "black", borderRadius: 4, padding: 6 }}
android_ripple={{ color: "gray" }}
onPress={endModalOpen}
>
<Text style={{ color: "white" }}>Select time</Text>
</Pressable>
{isEndOpened && (
<DateTimePicker
value={endDate ? endDate : new Date()}
onChange={(e) => {
setEndDate(new Date(e.nativeEvent.timestamp));
console.log(new Date(e.nativeEvent.timestamp));
setEndDateTitle(
new Date(e.nativeEvent.timestamp).toUTCString()
);
setIsEndOpened(false);
}}
/>
)}
</View>
</View>
<View>
<Pressable
style={{
backgroundColor: "black",
borderRadius: 4,
padding: 6,
margin: 12,
}}
android_ripple={{ color: "gray" }}
onPress={selectImages}
>
<Text style={{ color: "white" }}>
Select Images <MaterialCommunityIcons name="camera" />
</Text>
</Pressable>
</View>
{finalImages.length === 0 && (
<Text style={{ textAlign: "center" }}>
You haven't picked any image yet 😥
</Text>
)}
{finalImages.length > 0 && (
<>
<Text
style={{
fontWeight: "600",
textAlign: "center",
verticalAlign: "middle",
margin: 4,
}}
>
You have picked already {finalImages.length} pictures 😮
</Text>
<View
style={{
gap: 6,
flexWrap: "wrap",
flexDirection: "row",
justifyContent: "center",
}}
>
{finalImages.map((image, index) => (
<Image
key={index}
source={{ uri: image.uri }}
style={{
width: 50,
height: 50,
objectFit: "cover",
margin: 5,
}}
/>
))}
</View>
</>
)}
<View>
<Text style={{ fontWeight: "600", padding: 6, textAlign: "center" }}>
Choose the place on map that you visited:
</Text>
<MapView
scrollEnabled={false}
zoomEnabled={false}
initialRegion={currentLocation}
style={{
width: "100%",
height: Dimensions.get("window").height / 3,
}}
>
{markerCoords && <Marker coordinate={markerCoords} />}
</MapView>
<View
style={{
flexDirection: "row",
justifyContent: "space-around",
gap: 6,
}}
>
<Pressable
onPress={getLocationPermission}
android_ripple={{ color: "gray" }}
style={{
padding: 5,
margin: 5,
backgroundColor: "black",
alignItems: "center",
borderRadius: 5,
}}
>
<Text style={{ color: "white" }}>
Share Your Location{" "}
<IonIcons name="location" style={{ fontSize: 16 }} />
</Text>
</Pressable>
<Pressable
onPress={navigateToMapSelect}
android_ripple={{ color: "gray" }}
style={{
padding: 5,
margin: 5,
backgroundColor: "black",
alignItems: "center",
borderRadius: 5,
}}
>
<Text style={{ color: "white" }}>
Select on Map <IonIcons name="map" style={{ fontSize: 16 }} />
</Text>
</Pressable>
</View>
</View>
<Pressable
style={{ backgroundColor: "black", padding: 6, borderRadius: 4 }}
onPress={() => {
console.log(route.params);
}}
>
<Text style={{ color: "white", textAlign: "center" }}>Submit</Text>
</Pressable>
</View>
</ScrollView>
);
};
export default CreateForm;
import React, { useEffect, useState } from "react";
import { Pressable, Text, View } from "react-native";
import MapView, { Marker } from "react-native-maps";
import IonIcons from "@expo/vector-icons/Ionicons";
const MapSelect = ({ route, navigation }) => {
const [markerCoords, setMarkerCoords] = useState(null);
const [newMapLayout, setNewMapLayout] = useState(null);
const coordsForMap = route.params.coords;
const existingMarkerCoords = route.params.marker;
const selectPlaceOnMap = (e) => {
const coords = e.nativeEvent.coordinate;
const newMapsCoords = {
latitude: coords.latitude,
longitude: coords.longitude,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
};
setNewMapLayout(newMapsCoords);
setMarkerCoords(coords);
console.log(newMapsCoords);
console.log(coords);
};
const saveMarker = () => {
navigation.navigate("StackScreen", {
mapLayout: newMapLayout,
markerCoords: markerCoords,
});
};
useEffect(() => {
if (existingMarkerCoords) {
setMarkerCoords(existingMarkerCoords);
}
}, [existingMarkerCoords]);
useEffect(() => {
navigation.setOptions(
{
headerRight: () => (
<Pressable onPress={saveMarker}>
<Text style={{ color: "white" }}>
Save <IonIcons name="save-sharp" />
</Text>
</Pressable>
),
},
[]
);
}, [saveMarker]); // Listen to changes in newMapLayout and markerCoords
return (
<View>
<MapView
initialRegion={coordsForMap}
style={{ width: "100%", height: "100%" }}
onPress={selectPlaceOnMap}
>
{markerCoords && <Marker coordinate={markerCoords} />}
</MapView>
</View>
);
};
export default MapSelect;
Well i did all my best, but actually my attempts didn't work. So I expect that after I save the marker, the MapView will display the place with the marker.
答案1
得分: 0
我已经修复了,唯一需要的是设置region。我猜今晚我不会清醒!
在initialRegion之后添加region!
<View>
<Text style={{ fontWeight: "600", padding: 6, textAlign: "center" }}>
选择你访问的地图上的位置:
</Text>
<MapView
scrollEnabled={false}
zoomEnabled={false}
initialRegion={initalCoords}
region={currentLocation}
style={{
width: "100%",
height: Dimensions.get("window").height / 3,
}}
>
{markerCoords && <Marker coordinate={markerCoords} />}
</MapView>
<View
style={{
flexDirection: "row",
justifyContent: "space-around",
gap: 6,
}}
>
<Pressable
onPress={getLocationPermission}
android_ripple={{ color: "gray" }}
style={{
padding: 5,
margin: 5,
backgroundColor: "black",
alignItems: "center",
borderRadius: 5,
}}
>
<Text style={{ color: "white" }}>
分享你的位置{" "}
<IonIcons name="location" style={{ fontSize: 16 }} />
</Text>
</Pressable>
<Pressable
onPress={navigateToMapSelect}
android_ripple={{ color: "gray" }}
style={{
padding: 5,
margin: 5,
backgroundColor: "black",
alignItems: "center",
borderRadius: 5,
}}
>
<Text style={{ color: "white" }}>
在地图上选择 <IonIcons name="map" style={{ fontSize: 16 }} />
</Text>
</Pressable>
</View>
</View>
英文:
I FIXED IT, THE ONLY THING NEEDED WAS TO SET region. I reckon I won't be sober this night !
BEYOND INITIALREGION ADD region !
<View>
<Text style={{ fontWeight: "600", padding: 6, textAlign: "center" }}>
Choose the place on map that you visited:
</Text>
<MapView
scrollEnabled={false}
zoomEnabled={false}
initialRegion={initalCoords}
region={currentLocation}
style={{
width: "100%",
height: Dimensions.get("window").height / 3,
}}
>
{markerCoords && <Marker coordinate={markerCoords} />}
</MapView>
<View
style={{
flexDirection: "row",
justifyContent: "space-around",
gap: 6,
}}
>
<Pressable
onPress={getLocationPermission}
android_ripple={{ color: "gray" }}
style={{
padding: 5,
margin: 5,
backgroundColor: "black",
alignItems: "center",
borderRadius: 5,
}}
>
<Text style={{ color: "white" }}>
Share Your Location{" "}
<IonIcons name="location" style={{ fontSize: 16 }} />
</Text>
</Pressable>
<Pressable
onPress={navigateToMapSelect}
android_ripple={{ color: "gray" }}
style={{
padding: 5,
margin: 5,
backgroundColor: "black",
alignItems: "center",
borderRadius: 5,
}}
>
<Text style={{ color: "white" }}>
Select on Map <IonIcons name="map" style={{ fontSize: 16 }} />
</Text>
</Pressable>
</View>
</View>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论