【问题标题】:React native gesture handler反应本机手势处理程序
【发布时间】:2021-11-08 15:02:03
【问题描述】:

我对 React 原生动画非常陌生。我正在尝试创建自定义底部表。我做了两个动画功能。这些函数将触发 transform translateY 位置变化。我创建了两个单独的按钮并调用这些函数。目标动画视图根据按钮按下时上下移​​动。我想滚动它们可拖动。如果动画视图拖到顶部,视图将向上,如果动画视图向下拖动,视图将向上。对于这个手势运动,我使用了来自react-native-gesture-handler 的PanGestureHandler。我在手势处理函数中使用了 bad-logic 并使用了这些函数,它向下拖动到底部,但当我尝试向上拖动时它没有上升。我真的不知道如何解决这个问题。

我在expo-snack分享我的代码

这是我的全部代码

import React, { useState } from "react";
    import {
      StyleSheet,
      Text,
      View,
      Dimensions,
      useWindowDimensions,
      SafeAreaView,
      Animated,
      Button,
    } from "react-native";
    
    import MapView from "react-native-maps";
    
    import {
      PanGestureHandler,
      PanGestureHandlerGestureEvent,
      TouchableOpacity,
    } from "react-native-gesture-handler";
    
    type AnimatedGHContext = {
      startX: number;
      startY: number;
    };
    
    const { width } = Dimensions.get("screen");
    
    const initialRegion = {
      latitudeDelta: 15,
      longitudeDelta: 15,
      latitude: 60.1098678,
      longitude: 24.7385084,
    };
    
    export default function App() {
      const { height } = useWindowDimensions();
      const [translateY] = useState(new Animated.Value(0));
    
      const bringUpActionSheet = () => {
        Animated.timing(translateY, {
          toValue: 0,
          duration: 500,
          useNativeDriver: true,
        }).start();
      };
    
      const closeDownBottomSheet = () => {
        Animated.timing(translateY, {
          toValue: 1,
          duration: 500,
          useNativeDriver: true,
        }).start();
      };
    
      const bottomSheetIntropolate = translateY.interpolate({
        inputRange: [0, 1],
        outputRange: [-height / 2.4 + 50, 0],
      });
    
      const animatedStyle = {
        transform: [
          {
            translateY: bottomSheetIntropolate,
          },
        ],
      };
    
      const gestureHandler = (e) => {
        console.log(e.nativeEvent.state); // THIS IS NOT GOOD CONDITION 
        if (e.nativeEvent.state) {
          closeDownBottomSheet(); 
        } else if (e.nativeEvent.state < 4) {
          bringUpActionSheet();
        }
      };
    
      return (
        <View style={{ flex: 1 }}>
          <MapView style={styles.mapStyle} initialRegion={initialRegion} />
          <PanGestureHandler onGestureEvent={gestureHandler}>
            <Animated.View
              style={[styles.container, { top: height * 0.7 }, animatedStyle]}
            >
              <Animated.View style={styles.grbber} />
              <SafeAreaView style={styles.wrapper}>
                <View style={styles.content}>
                  <Text style={styles.title}>I am scroll sheet</Text>
                  <TouchableOpacity
                    style={styles.button}
                    onPress={() => closeDownBottomSheet()}
                  >
                    <Text style={styles.title}>Close</Text>
                  </TouchableOpacity>
                  <TouchableOpacity
                    style={styles.button}
                    onPress={() => bringUpActionSheet()}
                  >
                    <Text style={styles.title}>Up</Text>
                  </TouchableOpacity>
                  <View style={styles.fakeContent} />
                </View>
              </SafeAreaView>
            </Animated.View>
          </PanGestureHandler>
        </View>
      );
    }
    
    const styles = StyleSheet.create({
      container: {
        position: "absolute",
        top: 0,
        left: 0,
        right: 0,
        backgroundColor: "white",
        shadowColor: "black",
        shadowOffset: {
          height: -6,
          width: 0,
        },
        shadowOpacity: 0.1,
        shadowRadius: 5,
        borderTopEndRadius: 15,
        borderTopLeftRadius: 15,
      },
      mapStyle: {
        width: width,
        height: 800,
      },
      content: {
        flex: 1,
        padding: 20,
      },
      title: {
        fontWeight: "400",
        fontSize: 22,
      },
      fakeContent: {
        flex: 1,
        height: 1000,
      },
      grbber: {
        width: 60,
        alignSelf: "center",
        marginTop: 5,
        borderTopWidth: 5,
        borderTopColor: "#aaa",
      },
      button: {
        alignItems: "center",
        justifyContent: "center",
        paddingVertical: 12,
        paddingHorizontal: 32,
        borderRadius: 4,
        elevation: 3,
        backgroundColor: "green",
        marginBottom: 10,
        height: 50,
      },
    });

【问题讨论】:

    标签: react-native animation gesture-recognition


    【解决方案1】:

    我认为你应该使用来自 react-native 库的动画视图和 panResponder 来处理运动并跟踪视图的 x 和 y 位置的值,并在 onPanResponderRelease 函数中更改 translateY 状态,检查这个:

    import React, { useState } from 'react';
    import {
      StyleSheet,
      Text,
      View,
      Dimensions,
      useWindowDimensions,
      SafeAreaView,
      Animated,
      PanResponder,
      Button,
    } from 'react-native';
    
    import MapView from 'react-native-maps';
    
    import {
      PanGestureHandler,
      PanGestureHandlerGestureEvent,
      TouchableOpacity,
    } from 'react-native-gesture-handler';
    
    type AnimatedGHContext = {
      startX: number,
      startY: number,
    };
    
    const { width } = Dimensions.get('screen');
    
    const initialRegion = {
      latitudeDelta: 15,
      longitudeDelta: 15,
      latitude: 60.1098678,
      longitude: 24.7385084,
    };
    
    export default function App() {
      const { height } = useWindowDimensions();
      const [translateY] = useState(new Animated.Value(0));
    
      const bringUpActionSheet = () => {
        Animated.timing(translateY, {
          toValue: 0,
          duration: 500,
          useNativeDriver: true,
        }).start();
      };
    
      const closeDownBottomSheet = () => {
        Animated.timing(translateY, {
          toValue: 1,
          duration: 500,
          useNativeDriver: true,
        }).start();
      };
    
      const bottomSheetIntropolate = translateY.interpolate({
        inputRange: [0, 1],
        outputRange: [-height / 2.4 + 50, 0],
      });
    
      const animatedStyle = {
        transform: [
          {
            translateY: bottomSheetIntropolate,
          },
        ],
      };
      [];
    
      const pan = React.useRef(new Animated.ValueXY()).current;
      const panResponder = React.useRef(
        PanResponder.create({
          onMoveShouldSetPanResponder: () => true,
          onPanResponderMove: Animated.event([null, { dx: pan.x, dy: pan.y }], {
            useNativeDriver: false,
          }),
          onPanResponderRelease: () => {
            //Add any functions you want here when the user lets go of the view
          },
        })
      ).current;
    
      return (
        <View style={{ flex: 1 }}>
          <MapView style={styles.mapStyle} initialRegion={initialRegion} />
          <Animated.View
            style={[styles.container, { top: height * 0.7 }, animatedStyle]}
            {...panResponder.panHandlers}>
            <Animated.View
              style={[
                {
                  transform: [{ translateX: pan.x }, { translateY: pan.y }],
                },
                styles.grbber,
              ]}
              {...panResponder.panHandlers}
            />
            <SafeAreaView style={styles.wrapper}>
              <View style={styles.content}>
                <Text style={styles.title}>I am scroll sheet</Text>
                <TouchableOpacity
                  style={styles.button}
                  onPress={() => closeDownBottomSheet()}>
                  <Text style={styles.title}>Close</Text>
                </TouchableOpacity>
                <TouchableOpacity
                  style={styles.button}
                  onPress={() => bringUpActionSheet()}>
                  <Text style={styles.title}>Up</Text>
                </TouchableOpacity>
                <View style={styles.fakeContent} />
              </View>
            </SafeAreaView>
          </Animated.View>
        </View>
      );
    }
    
    const styles = StyleSheet.create({
      container: {
        position: 'absolute',
        top: 0,
        left: 0,
        right: 0,
        backgroundColor: 'white',
        shadowColor: 'black',
        shadowOffset: {
          height: -6,
          width: 0,
        },
        shadowOpacity: 0.1,
        shadowRadius: 5,
        borderTopEndRadius: 15,
        borderTopLeftRadius: 15,
      },
      mapStyle: {
        width: width,
        height: 800,
      },
      content: {
        flex: 1,
        padding: 20,
      },
      title: {
        fontWeight: '400',
        fontSize: 22,
      },
      fakeContent: {
        flex: 1,
        height: 1000,
      },
      grbber: {
        flex: 1,
        width: 60,
        alignSelf: 'center',
        marginTop: 5,
        borderTopWidth: 5,
        borderTopColor: '#aaa',
      },
      button: {
        alignItems: 'center',
        justifyContent: 'center',
        paddingVertical: 12,
        paddingHorizontal: 32,
        borderRadius: 4,
        elevation: 3,
        backgroundColor: 'green',
        marginBottom: 10,
        height: 50,
      },
    });
    

    【讨论】:

      【解决方案2】:

      我做了这个逻辑。而且效果很好:)

        const gestureHandler = (e: PanGestureHandlerGestureEvent) => {
          if (e.nativeEvent.translationY > 0) {
            closeDownBottomSheet();
          } else if (e.nativeEvent.translationY < 0) {
            bringUpActionSheet();
          }
        };

      【讨论】:

        猜你喜欢
        • 2020-03-05
        • 2019-11-20
        • 2020-11-24
        • 2022-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-21
        相关资源
        最近更新 更多