地図の下部内容をabsoluteにして機能切り替えをスクロールで発動しないように変更

This commit is contained in:
harukin-expo-dev-env 2025-04-18 09:51:36 +00:00
parent 85de99e32d
commit b3cc5b6ede
3 changed files with 88 additions and 37 deletions

View File

@ -1,4 +1,4 @@
import React, { useEffect, useRef,useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { createStackNavigator } from "@react-navigation/stack"; import { createStackNavigator } from "@react-navigation/stack";
import { useWindowDimensions, Platform } from "react-native"; import { useWindowDimensions, Platform } from "react-native";
import Constants from "expo-constants"; import Constants from "expo-constants";
@ -50,8 +50,9 @@ export function MenuPage() {
}, []); }, []);
const scrollRef = useRef(null); const scrollRef = useRef(null);
const [mapHeight,setMapHeight] = useState(0); const [mapMode, setMapMode] = useState(false);
useEffect(()=>{ const [mapHeight, setMapHeight] = useState(0);
useEffect(() => {
const MapHeight = const MapHeight =
height - height -
tabBarHeight + tabBarHeight +
@ -60,12 +61,21 @@ export function MenuPage() {
((((width / 100) * 80) / 20) * 9 + 10 + 30); ((((width / 100) * 80) / 20) * 9 + 10 + 30);
setMapHeight(MapHeight); setMapHeight(MapHeight);
}, [height, tabBarHeight, width]); }, [height, tabBarHeight, width]);
const [MapFullHeight, setMapFullHeight] = useState(0);
useEffect(() => {
const MapFullHeight =
height -
tabBarHeight +
(Platform.OS == "android" ? Constants.statusBarHeight : 0);
setMapFullHeight(MapFullHeight);
}, [height, tabBarHeight, width]);
useEffect(() => { useEffect(() => {
const unsubscribe = addListener("tabPress", (e) => { const unsubscribe = addListener("tabPress", (e) => {
scrollRef.current.scrollTo({ scrollRef.current.scrollTo({
y: mapHeight - 80, y: mapHeight - 80,
animated: true, animated: true,
}); });
setMapMode(false);
AS.getItem("favoriteStation") AS.getItem("favoriteStation")
.then((d) => { .then((d) => {
const returnData = JSON.parse(d); const returnData = JSON.parse(d);
@ -87,7 +97,15 @@ export function MenuPage() {
gestureEnabled: true, gestureEnabled: true,
headerTransparent: true, headerTransparent: true,
}} }}
children={() => <Menu scrollRef={scrollRef} mapHeight={mapHeight} />} children={() => (
<Menu
scrollRef={scrollRef}
mapHeight={mapHeight}
MapFullHeight={MapFullHeight}
mapMode={mapMode}
setMapMode={setMapMode}
/>
)}
/> />
<Stack.Screen name="news" options={optionData} component={News} /> <Stack.Screen name="news" options={optionData} component={News} />
<Stack.Screen <Stack.Screen

View File

@ -1,3 +1,4 @@
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs";
import React, { useEffect, useRef } from "react"; import React, { useEffect, useRef } from "react";
import { View, TouchableOpacity, Text, LayoutAnimation } from "react-native"; import { View, TouchableOpacity, Text, LayoutAnimation } from "react-native";
import Ionicons from "react-native-vector-icons/Ionicons"; import Ionicons from "react-native-vector-icons/Ionicons";
@ -9,8 +10,10 @@ export const CarouselTypeChanger = ({
stationListMode, stationListMode,
setStationListMode, setStationListMode,
setSelectedCurrentStation, setSelectedCurrentStation,
mapMode,
setMapMode, setMapMode,
}) => { }) => {
const tabBarHeight = useBottomTabBarHeight();
const returnToDefaultMode = ()=>{ const returnToDefaultMode = ()=>{
LayoutAnimation.configureNext({ LayoutAnimation.configureNext({
duration: 300, duration: 300,
@ -26,7 +29,7 @@ export const CarouselTypeChanger = ({
setMapMode(false); setMapMode(false);
} }
return ( return (
<View style={{ width: "100%", height: 40, flexDirection: "row" }}> <View style={{ width: "100%", height: 40, flexDirection: "row", position: mapMode ? "absolute" : "relative", bottom: mapMode ? 0 : undefined}} key={"carouselTypeChanger"} >
<TouchableOpacity <TouchableOpacity
style={{ style={{
flex: 1, flex: 1,
@ -41,6 +44,12 @@ export const CarouselTypeChanger = ({
borderBottomRightRadius: stationListMode == "position" ? 0 : 20, borderBottomRightRadius: stationListMode == "position" ? 0 : 20,
}} }}
disabled={!locationStatus} disabled={!locationStatus}
onPressIn={() =>{
if (!position) return;
returnToDefaultMode();
setStationListMode("position");
}}
onPress={() => { onPress={() => {
if (!position) return; if (!position) return;
returnToDefaultMode(); returnToDefaultMode();
@ -76,7 +85,7 @@ export const CarouselTypeChanger = ({
onPressIn={() => returnToDefaultMode()} onPressIn={() => returnToDefaultMode()}
> >
<Ionicons <Ionicons
name="menu" name={!mapMode ? "menu" : "chevron-up-outline"}
size={30} size={30}
color="#0099CC" color="#0099CC"
style={{ marginHorizontal: 5 }} style={{ marginHorizontal: 5 }}
@ -95,6 +104,12 @@ export const CarouselTypeChanger = ({
borderBottomLeftRadius: stationListMode == "favorite" ? 0 : 20, borderBottomLeftRadius: stationListMode == "favorite" ? 0 : 20,
borderBottomRightRadius: stationListMode == "favorite" ? 0 : 20, borderBottomRightRadius: stationListMode == "favorite" ? 0 : 20,
}} }}
onPressIn={() => {
returnToDefaultMode();
// お気に入りリスト更新
setStationListMode("favorite");
setSelectedCurrentStation(0);
}}
onPress={() => { onPress={() => {
returnToDefaultMode(); returnToDefaultMode();
// お気に入りリスト更新 // お気に入りリスト更新

80
menu.js
View File

@ -33,32 +33,20 @@ configureReanimatedLogger({
level: ReanimatedLogLevel.error, // Set the log level to error level: ReanimatedLogLevel.error, // Set the log level to error
strict: true, // Reanimated runs in strict mode by default strict: true, // Reanimated runs in strict mode by default
}); });
export default function Menu({ scrollRef, mapHeight }) { export default function Menu({ scrollRef, mapHeight, MapFullHeight, mapMode, setMapMode }) {
const { navigate, addListener, isFocused } = useNavigation(); const { navigate, addListener, isFocused } = useNavigation();
const { favoriteStation } = useFavoriteStation(); const { favoriteStation } = useFavoriteStation();
const { originalStationList } = useStationList(); const { originalStationList } = useStationList();
const { height, width } = useWindowDimensions(); const { height, width } = useWindowDimensions();
const { bottom, left, right, top } = useSafeAreaInsets(); const { bottom, left, right, top } = useSafeAreaInsets();
const [mapMode, setMapMode] = useState(false);
const tabBarHeight = useBottomTabBarHeight(); const tabBarHeight = useBottomTabBarHeight();
const [stationListMode, setStationListMode] = useState( const [stationListMode, setStationListMode] = useState(
/*<"position"|"favorite">*/ "position" /*<"position"|"favorite">*/ "position"
); );
const mapsRef = useRef(null); const mapsRef = useRef(null);
const MapHeight =
height -
tabBarHeight +
(Platform.OS == "android" ? Constants.statusBarHeight : 0) -
100 -
((((width / 100) * 80) / 20) * 9 + 10 + 30);
const MapFullHeight =
height -
tabBarHeight +
(Platform.OS == "android" ? Constants.statusBarHeight : 0) -
100;
const returnToTop = (bool = true) => { const returnToTop = (bool = true) => {
scrollRef.current.scrollTo({ scrollRef.current.scrollTo({
y: mapHeight > 80 ?mapHeight - 80 :0, y: mapHeight > 80 ? mapHeight - 80 : 0,
animated: bool, animated: bool,
}); });
}; };
@ -69,11 +57,12 @@ export default function Menu({ scrollRef, mapHeight }) {
}); });
}; };
useEffect(() => { useEffect(() => {
setTimeout(()=>{ setTimeout(() => {
returnToTop(false); returnToTop(false);
}, 10); }, 10);
}, [mapHeight]); }, [mapHeight]);
const returnToDefaultMode = () => { const [scrollStartPosition, setScrollStartPosition] = useState(0);
const onScrollBeginDrag = (e) => {
LayoutAnimation.configureNext({ LayoutAnimation.configureNext({
duration: 300, duration: 300,
create: { create: {
@ -85,6 +74,7 @@ export default function Menu({ scrollRef, mapHeight }) {
property: LayoutAnimation.Properties.opacity, property: LayoutAnimation.Properties.opacity,
}, },
}); });
setScrollStartPosition(e.nativeEvent.contentOffset.y);
setMapMode(false); setMapMode(false);
}; };
//現在地基準の駅名標リストアップ機能 //現在地基準の駅名標リストアップ機能
@ -189,12 +179,22 @@ export default function Menu({ scrollRef, mapHeight }) {
snapToStart={false} snapToStart={false}
snapToEnd={false} snapToEnd={false}
decelerationRate={"normal"} decelerationRate={"normal"}
snapToOffsets={[MapHeight - 80]} snapToOffsets={[mapHeight - 80]}
onScrollBeginDrag={() => returnToDefaultMode()} onScrollBeginDrag={onScrollBeginDrag}
onScrollEndDrag={(e) => {
console.log(e.nativeEvent.velocity);
if (e.nativeEvent.contentOffset.y < mapHeight - 80) {
if (scrollStartPosition > e.nativeEvent.contentOffset.y) {
goToMap();
} else {
returnToTop();
}
}
}}
> >
<MapView <MapView
ref={mapsRef} ref={mapsRef}
style={{ width: "100%", height: mapMode ? MapFullHeight : MapHeight }} style={{ width: "100%", height: mapMode ? MapFullHeight : mapHeight }}
showsUserLocation={true} showsUserLocation={true}
loadingEnabled={true} loadingEnabled={true}
showsMyLocationButton={false} showsMyLocationButton={false}
@ -261,17 +261,21 @@ export default function Menu({ scrollRef, mapHeight }) {
/> />
))} ))}
</MapView> </MapView>
<CarouselTypeChanger {!mapMode && (
{...{ <CarouselTypeChanger
locationStatus, {...{
position, locationStatus,
mapsRef, position,
stationListMode, mapsRef,
setStationListMode, stationListMode,
setSelectedCurrentStation: setListIndex, setStationListMode,
setMapMode, setSelectedCurrentStation: setListIndex,
}} mapMode,
/> setMapMode,
}}
/>
)}
{listUpStation.length != 0 && originalStationList.length != 0 && ( {listUpStation.length != 0 && originalStationList.length != 0 && (
<> <>
<CarouselBox <CarouselBox
@ -298,6 +302,20 @@ export default function Menu({ scrollRef, mapHeight }) {
<JRSTraInfoBox /> <JRSTraInfoBox />
<FixedContentBottom navigate={navigate} /> <FixedContentBottom navigate={navigate} />
</ScrollView> </ScrollView>
{mapMode && (
<CarouselTypeChanger
{...{
locationStatus,
position,
mapsRef,
stationListMode,
setStationListMode,
setSelectedCurrentStation: setListIndex,
mapMode,
setMapMode,
}}
/>
)}
</View> </View>
); );
} }