【问题标题】:Drag up a ScrollView then continue scroll in React Native向上拖动一个 ScrollView,然后在 React Native 中继续滚动
【发布时间】:2019-04-30 14:32:22
【问题描述】:

我想要什么 (GIF)

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

我想要什么(文字)

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

我想要的是向上拖动 scrollview,然后,当它到达某个位置时,将 drag touch event 发送到 scrollview 本身,这样它就可以继续滚动。

我的尝试

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

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

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

那么,你能给我一些提示来实现这一点吗:)?

谢谢,

【问题讨论】:

  • 条件渲染怎么样?您首先将您的内容包装在&lt;View /&gt; 中,然后将其设为绝对位置。拖动时,您会检测它是否已获得全屏空间。然后,您呈现您的内容,但在 &lt;ScrollView /&gt; 内,而不是具有滚动功能。由于本方案不涉及padding,只要拖拽的view没有占据整个屏幕高度,就可以点击后面的内容。
  • 嘿大卫。你最终解决了你的问题吗?我现在也面临着同样的挑战。链接到我的问题:stackoverflow.com/questions/55082289/…
  • 我已经开始对这个问题进行赏金,因为我在网上找不到任何东西来实现这一点。有人可以提供一个解决方案,重新创建谷歌地图应用程序中显示的界面,并通过滚动正常运行吗?包含的 gif 仍然是当前版本,因此可能值得下载以仔细查看。有关尝试创建此 UI 的复杂性/错综复杂性的更多详细信息,请参阅@GilbertNwaiwu 的问题。
  • 新的 iOS 13 的“查找我的”应用还具有一个可滚动的叠加层,当您到达 scoll 视图的顶部时会向下拖动它:imgur.com/a/gg84IPo
  • 我发现这个库看起来像是在做你需要的事情octopitus.github.io/rn-sliding-up-panel。我将构建一个项目并进行演示

标签: reactjs react-native mobile-application react-native-scrollview


【解决方案1】:

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

演示:

解释:

基本思想是将地图始终保持在叠加层的背景中。叠加层是绝对定位的并包含两个视图。一个 View 是透明的,我们仍然可以看到和控制地图,另一个 View 包含实际的 ScrollView。诀窍是设置父叠加层的pointerEvents="box-none" 并使用我们想要与地图交互的视图的pointerEvents="none" 禁用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 变为全屏。因此我们监听ScrollView的onScroll方法。请参阅下面的代码和 cmets:

  _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 的 scrollEventThrottle 属性,我们可以控制调用 _onScroll 方法的频率。 (这里你可能需要微调)

完整的代码和工作零食

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

【讨论】:

  • 这个解决方案的问题是两个滚动视图同时接收触摸事件,这会产生异常快速的滚动。这也意味着子视图在您拉起它时会移动。对于滚动视图解决方案,这是一项巨大的努力,我很感谢您花时间回答问题,但除非有办法解决这个问题并且不会限制效果,否则我认为它还没有完全实现。
  • @jskidd3 只有一个 ScrollView。快速滚动是由于 _onScroll 函数是如何实现的。正如我所说,这只是一个工作示例,而不是完美的解决方案。如果我有时间,我会进一步优化它。
  • 感谢蒂姆,这无疑是一个很好的起点。稍后我会玩,看看我是否可以进一步调整答案
  • 我明白,但恐怕我花了很多时间试图调整答案以避免滚动子视图,但这似乎不可能。在此基础上,当前形式的答案并没有为问题提供足够好的解决方案。我确信 Google 地图示例是使用自定义 PanResponder 完成的。
  • The solution doesn't work。我知道赏金系统是如何工作的,在提供在两个平台上复制示例的解决方案之前,我不会奖励全部赏金。这对 OP 以及将来找到此答案的其他人都是一种伤害。 编辑:海报已删除 cmets - 我没有回复自己
【解决方案2】:

我认为最好将 MapView 和 BottomView 合二为一ScrollView

它将保存自然滚动行为并防止向下滚动时出现白色条纹或向上滚动时顶部视图消失等副作用。这里的主要问题是如何为MapView 制作“冻结”效果。

通过将MapView 内的Animated 容器相对于滚动事件转换来使用视差效果非常好。我认为Animated libraryAnimatable components 将是解决此类问题的好方法:

   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

您可以在此处查看完整示例:Code example

Screen capture

【讨论】:

    猜你喜欢
    • 2022-12-04
    • 2018-09-04
    • 2019-07-16
    • 2018-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    • 1970-01-01
    相关资源
    最近更新 更多