React Native地图切换日期时如何关闭Callout弹窗?
解决React Native Maps切换日期时关闭所有Callout弹窗的问题
在使用react-native-maps开发演出指南应用时,切换日期(点击"Next/Previous day's gigs"按钮)后,需要自动关闭所有当前打开的Callout弹窗,可通过以下方式实现:
核心方案:利用MapView的ref调用deselectAllMarkers()
react-native-maps的MapView组件提供了deselectAllMarkers()方法,调用后会取消所有标记的选中状态,从而自动关闭对应的Callout弹窗。
具体实现步骤:
- 创建MapView的ref:使用
useRef钩子创建指向MapView的引用。 - 修改日期切换函数:在
addDays函数中,先调用ref的deselectAllMarkers()方法,再更新日期状态。
修改后的GigMap.js代码:
import { useState, useMemo, useRef } from "react"; // 新增useRef导入 import { StyleSheet, Text, View, Pressable, Image, TouchableOpacity, } from "react-native"; import MapView from "react-native-maps"; import { Marker, Callout } from "react-native-maps"; import CalloutView from "./CalloutView"; import { mapStyle } from "../util/mapStyle"; import { useGigs } from "../hooks/useGigs"; import { AntDesign } from "@expo/vector-icons"; const GigMap = ({ navigation }) => { const [selectedDateMs, setSelectedDateMs] = useState(Date.now()); const gigs = useGigs(); const mapRef = useRef(null); // 新增MapView的ref // 生成格式为'Dec 20 2022'的日期字符串 const selectedDateString = useMemo(() => { const date = new Date(selectedDateMs); const dateToString = date.toString().slice(0,15) return dateToString }, [selectedDateMs]); // 筛选出当日演出 const gigsToday = gigs.filter((gig) => { const gigDate1 = new Date(gig.dateAndTime.seconds*1000) const gigDate2 = gigDate1.toString().slice(0,15) return gigDate2 === selectedDateString }) // 增减日期 const addDays = (amount) => { // 先关闭所有Callout弹窗 if (mapRef.current) { mapRef.current.deselectAllMarkers(); } setSelectedDateMs((curr) => curr + 1000 * 60 * 60 * 24 * amount); }; return ( <View style={styles.container}> <Text style={styles.headerText}>{`Gigs on ${selectedDateString}`}</Text> <View style={styles.imageText}> <Text style = {styles.subHeader}>Tap on</Text> <Image style={styles.image} source={require("../assets/Icon_Gold_48x48.png")} /> <Text style = {styles.subHeader}> to see gig info</Text> </View> <MapView ref={mapRef} // 绑定ref到MapView initialRegion={{ latitude: -41.29416, longitude: 174.77782, latitudeDelta: 0.03, longitudeDelta: 0.03, }} style={styles.map} customMapStyle={mapStyle} > {gigsToday.map((gig, i) => ( <Marker key={i} coordinate={{ latitude: gig.location.latitude, longitude: gig.location.longitude, }} image={require("../assets/Icon_Gold_48x48.png")} description = 'test' > <Callout style={styles.callout} tooltip={true} onPress={() => navigation.navigate("GigDetails", { venue: gig.venue, date: selectedDateString, gigName: gig.gigName, image: gig.image }) } > <CalloutView venue={gig.venue} gigName={gig.gigName} genre = {gig.genre} /> </Callout> </Marker> ))} </MapView> <View style={styles.buttonOptions}> <TouchableOpacity onPress={() => addDays(-1)} style = {styles.touchable}> <AntDesign name="caretleft" size={36} color="#778899" /> <Text style = {{fontFamily:'Helvetica-Neue', color:'#778899'}}>Previous day's gigs</Text> </TouchableOpacity> <TouchableOpacity onPress={() => addDays(1)} style = {styles.touchable}> <AntDesign name="caretright" size={36} color="#778899" /> <Text style = {{fontFamily:'Helvetica-Neue',color:'#778899'}}>Next day's gigs</Text> </TouchableOpacity> </View> </View> ); };
原理说明
deselectAllMarkers()是react-native-maps内置方法,会遍历所有标记并取消它们的选中状态。由于Callout弹窗的显示依赖标记的选中状态,标记取消选中后,对应的Callout会自动关闭。这种方式无需额外管理每个标记的状态,简洁高效。
内容的提问来源于stack exchange,提问作者Josh Simon
相关产品推荐
相关产品推荐

