Панель Google Maps с React Native - PullRequest
       38

Панель Google Maps с React Native

0 голосов
/ 14 января 2019

Я пытаюсь скопировать панель Google Maps Swipe Panel («Исследуйте Лондон») или что-то подобное. Панель следует открывать и закрывать, проводя пальцем, а при открытии внутреннее содержимое должно прокручиваться, т. Е. Внутри ScrollView, а затем, когда ScrollView находится сверху, прокрутка отключается, и панель может закрываться.

enter image description here

В настоящее время я использую плагин rn-sliding-up-panel для своего пролистывания Panel с дочерним компонентом ScrollView. Затем я нахожу положение ScrollView, если оно равно 0 и пользователь проводит пальцем вниз, я закрываю панель.

Однако на устройствах Android и iOS это выглядит довольно некорректно. Иногда он придерживается позиции 0 в ScrollView.

Кому-нибудь удалось построить нечто подобное? Может быть, я на правильном пути, и это требует доработки? Или есть лучший плагин там?

Любой совет или примеры будут очень ценны.

1 Ответ

0 голосов
/ 10 июня 2019
class ssss extends Component {
  constructor(props) {
    super(props);
    this.state = {
      position: new Animated.Value(props.isOpen ? 0 : height),
      opacity: new Animated.Value(0),
      height: defaultHeight,
      expanded: false,
      visible: props.isOpen
    };
  }

  // When user starts pulling popup previous height gets stored here
  // to help us calculate new height value during and after pulling
  _previousHeight = 0;

  componentDidMount() {
    // Initialize PanResponder to handle move gestures
    this._panResponder = PanResponder.create({
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponder: (evt, gestureState) => {
        const { dx, dy } = gestureState;
        // Ignore taps
        if (dx !== 0 && dy === 0) {
          return true;
        }
        return false;
      },
      onPanResponderGrant: (evt, gestureState) => {
        // Store previous height before user changed it
        this._previousHeight = this.state.height;
      },
      onPanResponderMove: (evt, gestureState) => {
        // Pull delta and velocity values for y axis from gestureState
        const { dy, vy } = gestureState;
        // Subtract delta y from previous height to get new height
        let newHeight = this._previousHeight - dy;

        // Animate heigh change so it looks smooth
        LayoutAnimation.easeInEaseOut();

        // Switch to expanded mode if popup pulled up above 80% mark
        if (newHeight > 600 - 600 / 5) {
          this.setState({ expanded: true });
        } else {
          this.setState({ expanded: false });
        }

        // Expand to full height if pulled up rapidly
        if (vy < -0.75) {
          this.setState({
            expanded: true,
            height: height * 0.65
          });
        }

        // Close if pulled down rapidly
        else if (vy > 0.75) {
          this.props.onClose();
        }
        // Close if pulled below 95% mark of default height
        else if (newHeight < defaultHeight * 0.95) {
          this.props.onClose();
        }
        // Limit max height to screen height
        else if (newHeight > 600) {
          this.setState({ height: height * 0.65 });
        } else {
          this.setState({ height: newHeight });
        }
      },
      onPanResponderTerminationRequest: (evt, gestureState) => true,
      onPanResponderRelease: (evt, gestureState) => {
        const { dy } = gestureState;
        const newHeight = this._previousHeight - dy;

        // Close if pulled below default height
        if (newHeight < defaultHeight) {
          this.props.onClose();
        }

        // Update previous height
        this._previousHeight = this.state.height;
      },
      onShouldBlockNativeResponder: (evt, gestureState) => {
        // Returns whether this component should block native components from becoming the JS
        // responder. Returns true by default. Is currently only supported on android.
        return true;
      }
    });
  }

  // Handle isOpen changes to either open or close popup
  componentWillReceiveProps(nextProps) {
    // isOpen prop changed to true from false
    if (!this.props.isOpen && nextProps.isOpen) {
      this.animateOpen();
    }
    // isOpen prop changed to false from true
    else if (this.props.isOpen && !nextProps.isOpen) {
      this.animateClose();
    }
  }

  // Open popup
  animateOpen() {
    // Update state first
    this.setState({ visible: true }, () => {
      Animated.parallel([
        // Animate opacity
        Animated.timing(
          this.state.opacity,
          { toValue: 0.5 } // semi-transparent
        ),
        // And slide up
        Animated.timing(
          this.state.position,
          { toValue: 0 } // top of the screen
        )
      ]).start();
    });
  }

  // Close popup
  animateClose() {
    Animated.parallel([
      // Animate opacity
      Animated.timing(
        this.state.opacity,
        { toValue: 0 } // transparent
      ),
      // Slide down
      Animated.timing(
        this.state.position,
        { toValue: height } // bottom of the screen
      )
    ]).start(() =>
      this.setState({
        // Reset to default values
        height: defaultHeight,
        expanded: false,
        visible: false
      })
    );
  }

  render() {
    // Render nothing if not visible
    if (!this.state.visible) {
      return null;
    }
    return (
      <View style={styles.container}>
        {/* Closes popup if user taps on semi-transparent backdrop */}
        <TouchableWithoutFeedback onPress={this.props.onClose}>
          <Animated.View
            style={[styles.backdrop, { opacity: this.state.opacity }]}
          />
        </TouchableWithoutFeedback>
        <Animated.View
          style={[
            styles.modal,
            {
              // Animates height
              height: this.state.height,
              // Animates position on the screen
              transform: [
                { translateY: this.state.position },
                { translateX: 0 }
              ]
            }
          ]}
        >
          {/* Content */}
          <View style={styles.content}>
            <View
              style={[styles.topUpContainer]}
              {...this._panResponder.panHandlers}
            >
              <View style={styles.hookerContainer}>
                <View style={styles.hooker} />
              </View>
              {/* Your content comes here */}
            </View>
          </View>
        </Animated.View>
      </View>
    );
  }
}

Это может помочь вам

...