Android 带有React Native的Google地图面板

Android 带有React Native的Google地图面板,android,reactjs,google-maps,react-native,swipe-gesture,Android,Reactjs,Google Maps,React Native,Swipe Gesture,我试图复制谷歌地图滑动面板(“探索伦敦城”)或类似的东西。面板应通过滑动打开和关闭,打开时,内部内容应滚动,即在滚动视图内,然后当滚动视图位于顶部时,滚动被禁用,面板可关闭 目前,我正在使用rn向上滑动面板插件进行面板滑动,子组件为ScrollView。然后我找到ScrollView的位置,如果它在0,并且用户正在向下滑动,我关闭面板 然而,在Android和iOS设备上,这似乎都有相当多的缺陷。有时它会在ScrollView中停留在位置0 有没有人建造过类似的东西?也许我在正确的轨道上,它需

我试图复制谷歌地图滑动面板(“探索伦敦城”)或类似的东西。面板应通过滑动打开和关闭,打开时,内部内容应滚动,即在滚动视图内,然后当滚动视图位于顶部时,滚动被禁用,面板可关闭

目前,我正在使用
rn向上滑动面板
插件进行面板滑动,子组件为ScrollView。然后我找到ScrollView的位置,如果它在0,并且用户正在向下滑动,我关闭面板

然而,在Android和iOS设备上,这似乎都有相当多的缺陷。有时它会在ScrollView中停留在位置0

有没有人建造过类似的东西?也许我在正确的轨道上,它需要改进?还是有更好的插件

任何建议或示例都将非常有用。

类ssss扩展组件{
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>
    );
  }
}
建造师(道具){ 超级(道具); 此.state={ 位置:新的动画.Value(props.isOpen?0:高度), 不透明度:新的动画。值(0), 高度:默认高度, 扩展:错, 可见:props.isOpen }; } //当用户开始拉弹出窗口时,先前的高度存储在此处 //帮助我们在拉动期间和拉动之后计算新高度值 _以前的高度=0; componentDidMount(){ //初始化PanResponder以处理移动手势 这是.\u panResponder=panResponder.create({ onStartShouldSetPanResponder:(evt,手势状态)=>真, onMoveShouldSetPanResponder:(evt,手势状态)=>{ 常数{dx,dy}=gestureState; //忽略水龙头 如果(dx!==0&&dy==0){ 返回true; } 返回false; }, onPanResponderGrant:(evt,手势状态)=>{ //在用户更改之前存储以前的高度 this.\u previousHeight=this.state.height; }, onPanResponderMove:(evt,手势状态)=>{ //从gestureState拉出y轴的增量和速度值 常数{dy,vy}=手势状态; //从以前的高度中减去增量y以获得新高度 设newHeight=this.\u先前的height-dy; //设置高度变化的动画,使其看起来平滑 LayoutImation.easeInEaseOut(); //如果弹出窗口拉高到80%标记以上,则切换到扩展模式 如果(新高度>600-600/5){ this.setState({expanded:true}); }否则{ this.setState({expanded:false}); } //如果快速向上拉,则膨胀至全高 如果(vy<-0.75){ 这是我的国家({ 对,, 高度:高度*0.65 }); } //如果快速向下拉,则关闭 否则,如果(vy>0.75){ this.props.onClose(); } //如果拉至默认高度的95%标记以下,则关闭 否则如果(新高度<默认高度*0.95){ this.props.onClose(); } //将最大高度限制为屏幕高度 否则,如果(新高度>600){ this.setState({height:height*0.65}); }否则{ this.setState({height:newHeight}); } }, onPanResponderTerminationRequest:(evt,gestureState)=>true, onPanResponderRelease:(evt,手势状态)=>{ const{dy}=gestureState; const newHeight=此值。\ u先前的高度-dy; //如果拉至低于默认高度,则关闭 如果(新高度<默认高度){ this.props.onClose(); } //更新以前的高度 this.\u previousHeight=this.state.height; }, onShouldBlockNativeResponder:(evt,手势状态)=>{ //返回此组件是否应阻止本机组件成为JS //默认情况下返回true。当前仅在android上受支持。 返回true; } }); } //处理打开或关闭弹出窗口的等参线更改 组件将接收道具(下一步){ //isOpen属性从false更改为true 如果(!this.props.isOpen&&nextrops.isOpen){ 这个。animateOpen(); } //isOpen属性从true更改为false else if(this.props.isOpen&!nextrops.isOpen){ 这个。animateClose(); } } //打开弹出窗口 animateOpen(){ //首先更新状态 this.setState({visible:true},()=>{ 平行动画([ //设置不透明度动画 时间( 这个,状态,不透明度, {toValue:0.5}//半透明 ), //然后滑上去 时间( 这个州的位置, {toValue:0}//屏幕顶部 ) ]).start(); }); } //关闭弹出窗口 animateClose(){ 平行动画([ //设置不透明度动画 时间( 这个,状态,不透明度, {toValue:0}//透明 ), //滑落 时间( 这个州的位置, {toValue:height}//屏幕底部 ) ]).start(()=> 这是我的国家({ //重置为默认值 高度:默认高度, 扩展:错, 可见:假 }) ); } render(){ //如果不可见,则不渲染任何内容 如果(!this.state.visible){ 返回null; } 返回( {/*如果用户点击半透明背景,则关闭弹出窗口*/} {/*内容*/} {/*您的内容出现在这里*/} ); } }
这可能对你有帮助