gpt4 book ai didi

react-native - React native Reanimated 条件动画 View 移动

转载 作者:行者123 更新时间:2023-12-04 17:11:11 25 4
gpt4 key购买 nike

我真的很陌生 React-native-reanimated .我正在尝试创建一个这样的自定义底页 app .我正在使用 PanGestureHandler来自 react-native-gesture-handler用于移动动画 View 上下移动。对于 gestureHandler我正在使用 useAnimatedGestureHandler来自 react-native-reanimated 的 Prop .我想将动画 View 从起点移动到中间屏幕和屏幕底部。这是我的底部工作表起点 image ,当向下滚动卡片时,它应该像这样出现在屏幕中间 image ,再次向下滚动卡片,它将像这样底部 image .

我在条件 useAnimatedGestureHandler 上遇到困难onEnd 运动。目前我正在跟踪 onEnd 的 event.translationY并从中得出一个条件。

目前它是这样工作的:

当应用程序启动时,动画 View 位于屏幕顶部,如果我将卡片滚动到底部,它会移动到屏幕中间并且不会从屏幕中间向下移动,我可以将它从屏幕中间,或者如果我用力滚动到底部,它会一直滚动到底部,如果我尝试向上 ScrollView ,它不会到中间,它只会向上滚动以启动 View 。

我正在尝试根据条件设置屏幕尺寸,但是 I don't know how to make it.

我在 expo-snacks 中分享了我的代码

这是我的全部代码

import React, { useState, useEffect } from "react";
import { StyleSheet, useWindowDimensions, RefreshControl } from "react-native";
import MapView from "react-native-maps";
import styled from "styled-components";

import {
PanGestureHandler,
PanGestureHandlerGestureEvent,
FlatList,
} from "react-native-gesture-handler";

import Animated, {
useAnimatedGestureHandler,
useAnimatedStyle,
useSharedValue,
withTiming,
Easing,
withSpring,
} from "react-native-reanimated";

const initialRegion = {
latitudeDelta: 15,
longitudeDelta: 15,
latitude: 60.1098678,
longitude: 24.7385084,
};

const api =
"http://open-api.myhelsinki.fi/v1/events/?distance_filter=60.1699%2C24.9384%2C10&language_filter=en&limit=50";

export default function App() {
const { height } = useWindowDimensions();
const top = useSharedValue(height);
const [event, setEvent] = useState([]);
const [loading, setLoading] = useState(false);
const prevTop = useSharedValue(height * 0.5);
// This is Fetch Data
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(api);
const data = await response.json();
setEvent(data.data);
setLoading(false);
} catch (error) {
console.log("erro", error);
}
};

useEffect(() => {
fetchData();
}, []);

const animatedStyle = useAnimatedStyle(() => {
return {
top: top.value * 0.2,
bottom: 0,
};
});

const gestureHandler = useAnimatedGestureHandler(
{
onStart(_, context) {
context.translateY = top.value;
},
onActive(event, context) {
top.value = context.translateY + event.translationY;
},
onEnd(event, _) {
// THIS IS MY CONDITION OF ANIMATED VIEW
if (event.translationY > 0 && event.translationY < 400) {
console.log("middle-top", top.value);
console.log("middle-height", height);

top.value = withSpring(height * 2.5, {
duration: 500,
easing: Easing.inOut(Easing.ease),
});
} else if (event.translationY > 450 && event.translationY < 800) {
console.log("bottom-top", top.value);
console.log("bottom-height", height);
top.value = withSpring(height * 4, {
duration: 500,
easing: Easing.inOut(Easing.ease),
});
} else if (event.translationY < 0) {
console.log("start-top", top.value);
console.log("start-height", height);
top.value = withSpring(height, {
duration: 500,
easing: Easing.inOut(Easing.ease),
});
}
},
},
[top]
);

return (
<>
<MapView style={styles.mapStyle} initialRegion={initialRegion} />
<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.container, animatedStyle]}>
<Title>I am scroll sheet</Title>
<HeroFlatList
data={event}
refreshControl={
<RefreshControl
enabled={true}
refreshing={loading}
onRefresh={fetchData}
/>
}
keyExtractor={(_, index) => index.toString()}
renderItem={({ item, index }) => {
const image = item?.description.images.map((img) => img.url);
const startDate = item?.event_dates?.starting_day;
return (
<EventContainer key={index}>
<EventImage
source={{
uri:
image[0] ||
"https://res.cloudinary.com/drewzxzgc/image/upload/v1631085536/zma1beozwbdc8zqwfhdu.jpg",
}}
/>
<DescriptionContainer>
<Title ellipsizeMode="tail" numberOfLines={1}>
{item?.name?.en}
</Title>
<DescriptionText>
{item?.description?.intro || "No description available"}
</DescriptionText>
<DateText>{startDate}</DateText>
</DescriptionContainer>
</EventContainer>
);
}}
/>
</Animated.View>
</PanGestureHandler>
</>
);
}

const styles = StyleSheet.create({
container: {
position: "absolute",
left: 0,
right: 0,
top: 0,

backgroundColor: "white",
shadowOffset: {
height: -6,
width: 0,
},
shadowOpacity: 0.1,
shadowRadius: 5,
borderTopEndRadius: 15,
borderTopLeftRadius: 15,
},
mapStyle: {
flex: 1,
},
});

const HeroFlatList = styled(FlatList).attrs({
contentContainerStyle: {
flexGrow: 1,
},
})`
padding: 12px;
`;

const Title = styled.Text`
font-size: 16px;
font-weight: 700;
margin-bottom: 10px;
align-self: center;
padding: 10px;
`;

const DescriptionText = styled.Text`
font-size: 14px;
opacity: 0.7;
`;

const DateText = styled.Text`
font-size: 14px;
opacity: 0.8;
color: #0099cc;
`;

const EventImage = styled.Image`
width: 70px;
height: 70px;
border-radius: 70px;
margin-right: 20px;
`;

const DescriptionContainer = styled.View`
width: 200px;
`;

const EventContainer = styled(Animated.View)`
flex-direction: row;
padding: 20px;
margin-bottom: 10px;
border-radius: 20px;
background-color: #fff;
shadow-color: #000;
shadow-opacity: 0.3;
shadow-radius: 20px;
shadow-offset: 0 10px;
`;

技术资料

<表类="s-表"><头>科技版本<正文> react native 手势处理程序^1.10.3react-native-reanimated^2.2.0

最佳答案

不是完美的解决方案...添加了一个新的 sharedValue 来跟踪它是向上还是向下移动。

const prevTop = useSharedValue(height * 0.5);

以及手势结束时的相应代码。

      onEnd() {
if (top.value > prevTop.value) {
top.value = withTiming(height * 0.98);
} else {
top.value = withTiming(Math.min(200, top.value));
}
prevTop.value = top.value;
},

仍有改进的余地。

关于react-native - React native Reanimated 条件动画 View 移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69417186/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com