[英]PanResponder to change Card Y value and issue of moving out of screen
我是 react-native animation API 和 PanResponder API 的新手
我想創建谷歌地圖克隆 UI 和卡片動畫,在結果后顯示。
我想創建卡片,當用戶向上滑動時,卡片到達屏幕頂部,當用戶向下滑動時,卡片應調整為原始 position。
我想實現的谷歌地圖演示
我已經為此實現了一些代碼,但我面臨的問題是卡片在頂部方向上移出屏幕(在卡片到達頂部位置后向上滑動)。 有時,向下滑動有效,但並非總是如此。
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;
如果你想制作底片,那么你可以使用react-native-bottomsheet-reanimated
yarn add react-native-bottomsheet-reanimated
import React, { useEffect, useState } from "react";
import {
SafeAreaView,
View,
Text,
Dimensions,
PanResponder,
Animated,
StyleSheet
} from "react-native";
import { Searchbar, FAB } from "react-native-paper";
import MapView from "react-native-maps";
import * as Location from "expo-location";
import BottomSheet from "react-native-bottomsheet-reanimated";
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];
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")}
/>
<BottomSheet
bottomSheerColor="#FFFFFF"
initialPosition={"30%"} //200, 300
snapPoints={["30%","100%"]}
isBackDropDismisByPress={true}
isRoundBorderWithTipHeader={true}
containerStyle={{backgroundColor:"#0af"}}
header={
<View>
<Text style={styles.text}>Header</Text>
</View>
}
body={
<View style={styles.body}>
<Text>Hi</Text>
</View>
}
/>
</View>
)}
</SafeAreaView>
);
};
export default App;
const styles = StyleSheet.create({
body:{
justifyContent:"center",
alignItems:"center"
},
text:{
fontSize:20,
fontWeight:"bold"
}
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.