react-native 中的 BottomSheet 动画第一次无法正常工作

BottomSheet animation in react-native doesnt work properly for the first time

我正在尝试为我的 bottomsheet 创建这个动画,所以最初当我的主屏幕加载时,bottomsheet 会从下面弹出一个 spring 动画,然后当用户向上滑动时,bottomsheet 也会滑动上面有一个 spring 动画,如果用户向下滑动 bottomsheet 又会回到原来的位置,并有一个 spring 动画。

我面临的唯一问题是,我在初始弹出 spring 动画后进行的第一次向上滑动,向上滑动的动画并不顺利, 并且它在瞬间捕捉到上部位置而没有显示任何 spring 像动画

这是我的 BottomSheet 代码。

import * as React from "react";
import { SCREEN_HEIGHT } from "../../assets/constants";
import { StyleSheet, Animated, TextInput, View } from "react-native";
import { PanGestureHandler } from "react-native-gesture-handler";
import { Easing } from "react-native-reanimated";
import BottomSheetStack from "./BottomSheetStack";

export default class BottomSheet extends React.Component {
  constructor(props) {
    super(props);
    this.BottomSheet = new Animated.Value(0);
    this.state = {
      isOpen: false,
      isLoading: false,
      isPanChanged: false,
    };
  }

  componentDidMount() {
    setTimeout(() => this.animateTranslate(), 1000);
  }

  animateTranslate() {
    Animated.spring(this.BottomSheet, {
      toValue: 1,
      duration: 500,
      useNativeDriver: true,
      easing: Easing.ease,
    }).start();
  }

  translateDrawer() {
    return this.BottomSheet.interpolate({
      inputRange: [0, 1],
      outputRange: [SCREEN_HEIGHT, SCREEN_HEIGHT / 1.48],
    });
  }

  animateBottomSheetUp() {
    this.BottomSheet.setValue(0);
    Animated.spring(this.BottomSheet, {
      toValue: 1,
      duration: 100,
      useNativeDriver: true,
      easing: Easing.ease,
    }).start();
  }
  animateBottomSheetDown() {
    this.BottomSheet.setValue(0);
    Animated.spring(this.BottomSheet, {
      toValue: 1,
      duration: 100,
      useNativeDriver: true,
      easing: Easing.ease,
    }).start();
  }

  handlePanGesture(props) {
    this.setState({ isLoading: true });
    if (!this.state.isPanChanged) {
      this.setState({ isPanChanged: true });
    }
    if (!this.state.isOpen && props.nativeEvent.translationY > 0) {
      this.animateBottomSheetUp();
      this.setState({ isOpen: true });
    } else if (this.state.isOpen && props.nativeEvent.translationY < 0) {
      this.animateBottomSheetDown();
      this.setState({ isOpen: false });
    }
  }

  openBottomSheetHandler() {
    return this.BottomSheet.interpolate({
      inputRange: [0, 1],
      outputRange: [SCREEN_HEIGHT / 1.48, SCREEN_HEIGHT / 2.1],
    });
  }
  closeBottomSheetHandler() {
    return this.BottomSheet.interpolate({
      inputRange: [0, 1],
      outputRange: [SCREEN_HEIGHT / 2.1, SCREEN_HEIGHT / 1.48],
    });
  }

  render() {
    return (
      <PanGestureHandler
        onGestureEvent={(props) => this.handlePanGesture(props)}
      >
        <Animated.View
          style={{
            ...StyleSheet.absoluteFill,
            height: SCREEN_HEIGHT - SCREEN_HEIGHT / 2.2,
            backgroundColor: "#ffffff",
            elevation: 10,
            transform: [
              {
                translateY: !this.state.isLoading
                  ? this.translateDrawer()
                  : !this.state.isOpen && this.state.isPanChanged
                  ? this.openBottomSheetHandler()
                  : this.closeBottomSheetHandler(),
              },
            ],
            alignItems: "center",
            borderRadius: 15,
          }}
        >
          <View style={styles.bottomSheetLine} />
          <TextInput
            value={this.state.name}
            style={styles.searchBox}
            placeholder="Search"
            placeholderTextColor="#5DB075"
          />
          <BottomSheetStack {...this.props.navigation} />
        </Animated.View>
      </PanGestureHandler>
    );
  }
}

const styles = StyleSheet.create({
  searchBox: {
    height: 45,
    width: `85%`,
    backgroundColor: "#ffffff",
    borderRadius: 10,
    color: "#5DB075",
    paddingLeft: 20,
    fontSize: 14,
    letterSpacing: 0.5,
    top: 20,
    fontFamily: "regular",
    borderColor: "#5DB075",
    borderWidth: 1,
  },
  bottomSheetLine: {
    height: 5,
    backgroundColor: "#5DB075",
    width: 70,
    borderRadius: 5,
    top: 5,
  },
});

请给我一些关于如何实现这一目标的想法,或者可以用来实现这一目标的任何其他方法。

所以,显然,在某个地方我发现 spring 动画 toValue:1 实际上并没有上升到 1,它略微超过 1。这就是为什么我的动画表现得像我猜的那样。

解决这个问题的方法是,我只是将 toValue 更改为 animateBottomSheetUpanimateBottomSheetDown ,转到更高的值,即 toValue:2animateBottomSheetUp .

我的代码改动很小,看起来像这样,

我还从我的代码中删除了所有 this.BottomSheet.setValue(/*somevalue*/)

对于 animateBottomSheetUp:

  animateBottomSheetUp() {
    Animated.spring(this.BottomSheet, {
      toValue: 2,   // made this change from 1 to 2
      duration: 100,
      useNativeDriver: true,
      easing: Easing.ease,
    }).start();
  }

openBottomSheetHandler & closeBottomSheetHandler 现在看起来像这样,

  openBottomSheetHandler() {
    return this.BottomSheet.interpolate({
      inputRange: [1, 2],
      outputRange: [SCREEN_HEIGHT / 1.48, SCREEN_HEIGHT / 2.1],
    });
  }
  closeBottomSheetHandler() {
    return this.BottomSheet.interpolate({
      inputRange: [1, 2],
      outputRange: [SCREEN_HEIGHT / 1.48, SCREEN_HEIGHT / 2.1],
    });
  }

如果有人遇到同样的问题,我会发布这个答案,
虽然我已经解决了这个问题,但我仍然觉得必须有更好的方法来做到这一点,如果有人有更好的方法,请回答。 :-)