向上拖动 ScrollView 然后在 React Native 中继续滚动

IT技术 reactjs react-native mobile-application react-native-scrollview
2021-04-26 10:30:08

我想要什么 (GIF)

这是关于我想要实现的目标的(质量降低的)GIF。

在此处输入图片说明

我想要的(文字)

我有一个scrollview, 位于屏幕的一半。

我想要的是将其scrollview向上拖动,然后当它到达某个位置时,将其发送drag touch eventscrollview自身,以便它可以继续滚动。

我的尝试

  • 将滚动视图全屏放在前台,并在其contentContainerStyle. 它运行良好,但我无法单击它后面的视图。有没有办法点击滚动视图空白区域
  • 我还尝试检测滚动位置,以便相应地向上移动视图

    <ScrollView onScroll={event => moveScrollViewUpIfNeeded(event)}>
        ...
    </ScrollView>
    

    但是当我在 iOS 模拟器上测试它时没有用。事件甚至没有被触发。React Native Docs声明onScroll需要scrollEventThrottle工作。但是,scrollEventThrottle在 iOS 上可用就我而言,我也希望在 Android 上使用它。
    如果我成功实现了这一点,我应该面临另一个 UI 问题:向上拖动 ScrollView 时,如何在视图尚未到达所需位置时阻止它滚动?

所以,你能给我一些实现这一目标的提示:)?

谢谢,

2个回答

我已经尝试了几种选择。这是我的解决方案,在性能方面效果最好。当然,这只是一个工作示例,您可能需要进一步优化它以完全满足您的需求。

演示:

演示 Gif

解释:

基本思想是将地图始终保留在叠加层的背景中。叠加层是绝对定位的,包含两个视图。一个 View 是透明的,我们仍然可以看到和控制地图,另一个 View 包含实际的 ScrollView。诀窍是设置pointerEvents="box-none"父叠加层并禁用pointerEvents="none"我们想要与地图交互的 View 的pointerEvents

基本渲染方法:

  <SafeAreaView style={{flex: 1}}>
     <MapView
      initialRegion={region}
      style={{height: HEIGHT, width: WIDTH}}
      /> 
    <View  pointerEvents="box-none"style={{height: HEIGHT, width: WIDTH, position: 'absolute'}}>
      <View pointerEvents="none" style={{height: this.state.height, backgroundColor: 'transparent'}} />
      <View style={{ height: HEIGHT-this.state.height, backgroundColor: 'white'}}>
        <ScrollView onScroll={(e) => this._onScroll(e)} scrollEventThrottle={10} >
        -- content of scrollview goes here --- 
        </ScrollView>
      </View>
    </View>

  </SafeAreaView>

滚动功能:

如果我们向下滚动 ScrollView,我们希望缩小空视图,以便 ScrollView 变为全屏。因此我们监听onScrollScrollView方法。请参阅下面的代码和注释:

  _onScroll(e){
    // from the nativeEvent we can get the contentOffsett
    var offset_y = e.nativeEvent.contentOffset.y;
    if (offset_y > 0 ) {
     if (this.state.height>=0){
      // we are scrolling down the list, decrease height of the empty view
      this.setState({height: this.state.height-offset_y});
     }
    }
    if (offset_y <0){
      if (this.state.height <= this.state.mapHeight){
        // we are scrolling up the list, increase size of empty view/map view 
        this.setState({height: this.state.height-offset_y});
      }
    }
  }

使用 ScrollView 的scrollEventThrottleprop,我们可以控制_onScroll调用方法的频率(这里你可能需要微调)

完整代码和工作小吃

https://snack.expo.io/@tim1717/rnmapwithoverlay

我认为最好将 MapView 和 BottomView 放在一个ScrollView.

它将保存自然滚动行为并防止副作用,例如向下滚动时出现白色条纹或向上滚动时顶视图消失。这里的主要问题是如何为MapView.

通过将容器MapView内部Animated相对于滚动事件进行转换来使用视差效果是很好的我认为带有Animatable 组件的Animated 库将是解决此类问题的好方法:

   scroll = new Animated.Value(0)
   render() {
      return <Animated.ScrollView ...
          onScroll={Animated.event([{nativeEvent: {contentOffset: {y: this.scroll}}}], {useNativeDriver: true})}>

        <Animated.View 
              style={
                 { ...transform: 
                       [{translateY: Animated.multiply(this.scroll, 0.8)}]}}>
          <MapView />
        </Animated.View>
        <BottomView />
      </Animated.ScrollView>
    }

实际上,如果您不想要视差效果,则可以替换Animated.multiply(this.scroll, 0.8)this.scroll

您可以在此处查看完整示例:代码示例

屏幕截图