同时滚动两个组件

时间:2016-06-23 04:23:18

标签: ios react-native

我有一个显示时间表的应用程序。

当滚动包含计划的右ScrollView时,我希望包含时间的左ScrollView也可以滚动。

<ScrollView
    ref={'leftScroll'} />

<ScrollView
    ref={'rightScroll'}
    scrollEventThrottle={1}
    onScroll={(e) => this.refs.leftScroll.scrollTo({y: e.nativeEvent.contentOffset.y)}
    onMomentumScroll={(e) => this.refs.leftScroll.scrollTo({y: e.nativeEvent.contentOffset.y)} />

我们设法以这种方式滚动它,但它很慢且不连贯。 有没有办法完全同步这两个ScrollView的滚动?

这种设计的原因是时间需要始终固定在屏幕左侧,房间需要始终固定在顶部,这些需要根据滚动进行滚动在时间表中。

3 个答案:

答案 0 :(得分:3)

我有类似于你描述的要求 - ScrollView在左边有时间,ScrollView有一些正确的信息。

我能够通过对上面代码的一些小改动来实现平滑滚动在react-native中工作(尽管我没有使用onMomentumScroll)。在文档中,他们在scrollTo方法上提到了一个动画属性:https://facebook.github.io/react-native/docs/scrollview.html#scrollto

onScroll={(e) => this.refs.timeScroll.scrollTo({y: e.nativeEvent.contentOffset.y, animated: false})}

重要的是要注意,scrollEventThrottle={16}是必需的,否则再次滚动是不连贯的。 React-Native文档提到值1-16不明显 - 因此使用16。

编辑:

我以为我会来更新一下。我的上述解决方案在一定程度上起作用,但它仍然具有最小的延迟,最终会引人注意。

最后,我最终实现了Animated,因为它仅使用原生。

定义:

const yOffset = new Animated.Value(0);
const onScroll = Animated.event(
  [{ nativeEvent: { contentOffset: { y: yOffset } } }],
  { useNativeDriver: true }
);

创建方法:

viewTranslate() {
    return {
      transform: [{
        translateY: yOffset.interpolate({
          inputRange: [0,1],
          outputRange: [1,0]
        })
      }]
    };
  }

将样式指定给Animated.View:

<Animated.View style={this.viewTranslate()>...</Animated.View>

将事件分配给Animated.ScrollView:

<Animated.ScrollView scrollEventThrottle={1} onScroll={onScroll}>...</Animated.ScrollView>

答案 1 :(得分:2)

由于React Native目前的工作方式,我担心这很困难。

您的第一个ScrollView收到主线程上的滚动事件,并相应地滚动。然后React Native接受事件并将其发送到JS线程,以便可以在JS端处理,并且onScroll事件可以触发。 然后你的处理程序调用方法滚动你的第二个ScrollView,这意味着从JS线程安排一个新的事件在主线程上运行,这样就可以进行程序化滚动。

因此,由于所有这些调度和消息在这些线程之间传递,您的第二个ScrollView将始终落后于您经历的。

因此,如果您真的希望让它们同步,那么您将不得不求助于本机实现(这意味着iOS的实现和Android的另一个实现)。

一种可能的方法如下(iOS详细说明):

  • 写一个custom native module,其中有一种方法可以获得您希望保持同步的reactTag的{​​{1}} React.findNodeHandle(component)
  • 在您的自定义模块的原生端,您将能够使用ScrollView
  • 之类的内容获取指向ScrollView的指针
  • 然后是一个有趣的部分,你必须从那些UIScrollView *scrollView = [[[self bridge] uiManager] viewForReactTag:reactTag]挂钩到didScroll事件,以便你可以添加自定义逻辑以保持它们同步。您可以调动或替换UIScrollView(不要忘记将原始事件转发给原始代理)。我建议你仔细查看RCTScrollView以找到最适合的地方。

我希望你能得到这个想法;)这绝对不是一件轻而易举的事,你需要在iOS编程方面有丰富的经验。但这是学习新事物的好机会。

答案 2 :(得分:1)

我尝试了@adam_提出的Animated解决方案,但是我发现视图转换本身不允许剪切,因此最终不适用于具有固定标题和左列的表。动画将在这些动画上播放。

此外,当与平面列表一起使用时,由于它是纯视图转换,因此滚动时不会加载列,因此空白区域会滚动到屏幕上。

如果有人对此有任何线索,表示赞赏。