Я новичок в React-native Animation API и PanResponder API. Я хочу создать пользовательский интерфейс клонирования карт Google и анимацию карты, которая отображается после результатов. Я хочу создать карточку, и когда пользователь проведет пальцем вверх, карточка, которую вы дойдете до верхней части экрана, и когда пользователь проведет пальцем вниз, карточка должна измениться в размере до исходного положения. Демонстрация карт Google, которых я хочу достичь
Я реализовал часть кода для этого, но я сталкиваюсь с проблемой, например, когда карта выходит за пределы экрана в верхнем направлении (смахивание вверх после того, как карта достигнет верхнего положения). Иногда смахивание вниз работает, но не всегда.
Моя демонстрация
Expo Snack Link
Прил. js
import React, { useEffect, useState } from "react";
import {
SafeAreaView,
View,
Text,
Dimensions,
PanResponder,
Animated,
} from "react-native";
import { Searchbar, FAB } from "react-native-paper";
import MapView from "react-native-maps";
import * as Location from "expo-location";
const SCREEN_HEIGHT = Dimensions.get("window").height;
const SCREEN_WIDTH = Dimensions.get("window").width;
const App = () => {
const [latitute, setLatitute] = useState(0);
const [longitute, setLongitute] = useState(0);
const [isLoading, setIsLoading] = useState(true);
const pan = useState(
new Animated.ValueXY({ x: 0, y: SCREEN_HEIGHT - 200 })
)[0];
const panResponder = useState(
PanResponder.create({
onMoveShouldSetPanResponder: () => true,
onPanResponderGrant: () => {
pan.extractOffset();
return true;
},
onPanResponderMove: (e, gestureState) => {
pan.setValue({ x: 0, y: gestureState.dy });
},
onPanResponderRelease: (e, gestureState) => {
if (gestureState.moveY > SCREEN_HEIGHT - 200) {
Animated.spring(pan.y, {
toValue: 0,
tension: 1,
useNativeDriver: true,
}).start();
} else if (gestureState.moveY < 200) {
Animated.spring(pan.y, {
toValue: 0,
tension: 1,
useNativeDriver: true,
}).start();
} else if (gestureState.dy < 0) {
Animated.spring(pan.y, {
toValue: -SCREEN_HEIGHT + 200,
tension: 1,
useNativeDriver: true,
}).start();
} else if (gestureState.dy > 0) {
Animated.spring(pan.y, {
toValue: SCREEN_HEIGHT - 200,
tension: 1,
useNativeDriver: true,
}).start();
}
},
})
)[0];
const animatedHeight = {
transform: pan.getTranslateTransform(),
};
useEffect(() => {
(async () => {
let { status } = await Location.requestPermissionsAsync();
let location = await Location.getCurrentPositionAsync({});
console.log(location);
setLatitute(location.coords.latitude);
setLongitute(location.coords.longitude);
setIsLoading(false);
})();
}, []);
return (
<SafeAreaView
style={{
display: "flex",
flex: 1,
}}
>
{!isLoading && (
<View>
<MapView
style={{ width: SCREEN_WIDTH, height: SCREEN_HEIGHT }}
showsUserLocation
initialRegion={{
latitude: latitute,
longitude: longitute,
latitudeDelta: 0.01,
longitudeDelta: 0.01,
}}
/>
<Searchbar
placeholder="Search"
style={{
position: "absolute",
top: 10,
margin: 10,
}}
icon="menu"
onIconPress={() => {}}
/>
<FAB
style={{
position: "absolute",
top: SCREEN_HEIGHT * 0.8,
left: SCREEN_WIDTH * 0.8,
}}
icon="plus"
onPress={() => console.log("Pressed")}
/>
<Animated.View
style={[
animatedHeight,
{
position: "absolute",
right: 0,
left: 0,
width: SCREEN_WIDTH,
height: SCREEN_HEIGHT,
backgroundColor: "#0af",
borderTopLeftRadius: 25,
borderTopRightRadius: 25,
zIndex: 10,
},
]}
{...panResponder.panHandlers}
>
<View>
<Text>Hi</Text>
</View>
</Animated.View>
</View>
)}
</SafeAreaView>
);
};
export default App;