From cc87071500607ea0686da63358a5d9b83c0a9c60 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 11 Feb 2026 00:52:36 +0000 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=E3=83=9E=E3=83=83=E3=83=97=E7=A7=BB?= =?UTF-8?q?=E5=8B=95=E6=99=82=E3=81=AB=E3=83=9E=E3=83=BC=E3=82=AB=E3=83=BC?= =?UTF-8?q?=E3=81=AE=E5=90=B9=E3=81=8D=E5=87=BA=E3=81=97=E3=81=8C=E6=B6=88?= =?UTF-8?q?=E3=81=88=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit マーカーをタップして表示された吹き出し(callout)が、マップのパン・ズーム操作時に 自動的に消えてしまう問題を修正。onRegionChangeComplete で選択中のマーカーの showCallout() を再呼び出しすることで、ユーザーが明示的に閉じるまで吹き出しを 表示し続けるようにした。 吹き出しの明示的な解除方法: - マップの背景をタップ - 吹き出し自体をタップ - 別のマーカーをタップ(切り替え) https://claude.ai/code/session_01TuXxMDD3bmhRDQ5QN2NYxi --- app/(tabs)/map.tsx | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/app/(tabs)/map.tsx b/app/(tabs)/map.tsx index 69b94bb..0fd98cf 100644 --- a/app/(tabs)/map.tsx +++ b/app/(tabs)/map.tsx @@ -39,6 +39,7 @@ if (Platform.OS !== "web") { } type MapViewRef = import("react-native-maps").default; +type MapMarkerRef = { showCallout: () => void; hideCallout: () => void }; // アコーディオンコンテンツの最大高さ(アニメーション用) const ACCORDION_MAX_HEIGHT = 200; @@ -49,6 +50,8 @@ export default function MapScreen() { const [isFilterExpanded, setIsFilterExpanded] = useState(true); const mapRef = useRef(null); const [isFollowing, setIsFollowing] = useState(true); + const selectedMarkerIdRef = useRef(null); + const markerRefs = useRef>(new Map()); // アニメーション用の共有値(開いた状態で初期化) const rotateValue = useSharedValue(180); @@ -92,6 +95,36 @@ export default function MapScreen() { setIsFollowing(false); }, []); + // マーカーをタップしたら選択状態にする + const handleMarkerPress = useCallback((deviceId: string) => { + selectedMarkerIdRef.current = deviceId; + }, []); + + // マップ背景をタップしたら吹き出しを明示的に閉じる + const handleMapPress = useCallback(() => { + selectedMarkerIdRef.current = null; + }, []); + + // 吹き出しをタップしたら閉じる + const handleCalloutPress = useCallback((deviceId: string) => { + selectedMarkerIdRef.current = null; + const marker = markerRefs.current.get(deviceId); + if (marker) { + marker.hideCallout(); + } + }, []); + + // 地図の移動完了後に選択中のマーカーの吹き出しを再表示する + const handleRegionChangeComplete = useCallback(() => { + const markerId = selectedMarkerIdRef.current; + if (markerId) { + const marker = markerRefs.current.get(markerId); + if (marker) { + marker.showCallout(); + } + } + }, []); + // 現在地に戻るボタン const handleReturnToCurrentLocation = useCallback(() => { if (!mapRef.current) return; @@ -302,6 +335,8 @@ export default function MapScreen() { longitudeDelta: 0.5, }} onPanDrag={handleMapPanDrag} + onRegionChangeComplete={handleRegionChangeComplete} + onPress={handleMapPress} > {trajectories.map((trajectory) => ( @@ -314,10 +349,19 @@ export default function MapScreen() { )} {Marker && trajectory.latestPosition && ( { + if (ref) { + markerRefs.current.set(trajectory.deviceId, ref); + } else { + markerRefs.current.delete(trajectory.deviceId); + } + }} coordinate={trajectory.latestPosition} title={trajectory.deviceId} description="最新位置" pinColor={getDeviceColor(trajectory.deviceId, state.deviceIds)} + onPress={() => handleMarkerPress(trajectory.deviceId)} + onCalloutPress={() => handleCalloutPress(trajectory.deviceId)} /> )} From e62087c5a12255fe6a949778b5397f3e927a7a56 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 11 Feb 2026 01:22:11 +0000 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=E3=83=9E=E3=83=83=E3=83=97=E8=83=8C?= =?UTF-8?q?=E6=99=AF=E3=82=BF=E3=83=83=E3=83=97=E6=99=82=E3=81=AB=E5=90=B9?= =?UTF-8?q?=E3=81=8D=E5=87=BA=E3=81=97=E3=81=AEhideCallout()=E3=82=92?= =?UTF-8?q?=E5=91=BC=E3=81=B3=E5=87=BA=E3=81=99=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handleMapPressでselectedMarkerIdRef.currentをクリアするだけでなく、 選択中のマーカーがある場合にhideCallout()を呼び出して視覚的にも 吹き出しを確実に非表示にする。 https://claude.ai/code/session_01TuXxMDD3bmhRDQ5QN2NYxi --- app/(tabs)/map.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/(tabs)/map.tsx b/app/(tabs)/map.tsx index 0fd98cf..2ce19e1 100644 --- a/app/(tabs)/map.tsx +++ b/app/(tabs)/map.tsx @@ -102,6 +102,12 @@ export default function MapScreen() { // マップ背景をタップしたら吹き出しを明示的に閉じる const handleMapPress = useCallback(() => { + if (selectedMarkerIdRef.current) { + const marker = markerRefs.current.get(selectedMarkerIdRef.current); + if (marker) { + marker.hideCallout(); + } + } selectedMarkerIdRef.current = null; }, []); From 790302f62d1490437e66c67d07b11d45e468d394 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 11 Feb 2026 01:26:46 +0000 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20Marker=E3=82=BF=E3=83=83=E3=83=97?= =?UTF-8?q?=E6=99=82=E3=81=AE=E3=82=A4=E3=83=99=E3=83=B3=E3=83=88=E4=BC=9D?= =?UTF-8?q?=E6=92=AD=E3=82=92=E9=98=B2=E6=AD=A2=E3=81=97=E3=81=A6callout?= =?UTF-8?q?=E3=81=8C=E5=8D=B3=E5=BA=A7=E3=81=AB=E9=96=89=E3=81=98=E3=82=8B?= =?UTF-8?q?=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit iOSでMarkerのonPressが親のMapView.onPressに伝播し、handleMapPressが 呼ばれて吹き出しが即座に閉じてしまう問題を修正。MarkerにstopPropagation propを追加してイベントのバブリングを防止した。 https://claude.ai/code/session_01TuXxMDD3bmhRDQ5QN2NYxi --- app/(tabs)/map.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/(tabs)/map.tsx b/app/(tabs)/map.tsx index 2ce19e1..49b78a4 100644 --- a/app/(tabs)/map.tsx +++ b/app/(tabs)/map.tsx @@ -366,6 +366,7 @@ export default function MapScreen() { title={trajectory.deviceId} description="最新位置" pinColor={getDeviceColor(trajectory.deviceId, state.deviceIds)} + stopPropagation onPress={() => handleMarkerPress(trajectory.deviceId)} onCalloutPress={() => handleCalloutPress(trajectory.deviceId)} />