React Native嵌套ScrollView锁定

nic*_*las 31 javascript react-native

我正在尝试在React Native中嵌套ScrollViews; 带有嵌套垂直滚动的水平滚动.

这是一个例子:

var Test = React.createClass({
    render: function() {
        return (
            <ScrollView
                style={{width:320, height:568}}
                horizontal={true}
                pagingEnabled={true}>

                {times(3, (i) => {
                    return (
                        <View style={{width:320, height:568}}>

                            <ScrollView>
                                {times(20, (j) => {
                                    return (
                                        <View style={{width:320, height:100, backgroundColor:randomColor()}}/>
                                    );
                                })}
                            </ScrollView>

                        </View>
                    );
                })}

            </ScrollView>
        );
    },
});

AppRegistry.registerComponent('MyApp', () => Test);
Run Code Online (Sandbox Code Playgroud)

外部卷轴可以完美地工作,但是当它在移动时触摸它时,内部卷轴会粘住.我的意思是:如果你滚动,抬起你的手指,当它仍然以动量移动时再次触摸它,它停止并且根本不会对触摸动作做出反应.要滚动更多,您必须抬起手指再次触摸.

这是如此可重复,感觉与手势响应器有关.

有没有人见过这个问题?

我怎么会开始调试这个?有没有办法看到什么响应触摸,授予和释放,什么时候?

谢谢.

更新:

看起来它是响应者系统,通过将onResponderMove侦听器放在内部和外部滚动器上:

<ScrollView 
    onResponderMove={()=>{console.log('outer responding');}}
    ...

    <ScrollView
        onResponderMove={()=>{console.log('inner responding');}}>
        ...
Run Code Online (Sandbox Code Playgroud)

很明显,外部ScrollView正在抓住控制权.我想,问题是如何在尝试垂直滚动时阻止外部滚动条控制?为什么只有在您尝试滚动已经移动的内部ScrollView时才会发生这种情况?

Ada*_*dam 44

如果您正在使用 RN > 56.0,只需将此道具添加到您的滚动视图中:

<ScrollView nestedScrollEnabled = {true}>
 ......
  <ScrollView nestedScrollEnabled = {true}>
    .....
  </ScrollView>
</ScrollView>
Run Code Online (Sandbox Code Playgroud)

这是唯一对我有用的。

  • 我不敢相信这个解决方案是如此简单,或者我只是在这里找到它。无论如何,这真是太棒了,非常感谢!! (3认同)
  • 嵌套滚动是 iOS 的默认设置。https://reactnative.dev/docs/scrollview#nestedscrollenabled (2认同)
  • 在这种情况下,如果我滚动内部的,那么外部的也会滚动。有解决办法吗? (2认同)

Jos*_*ker 7

在内部响应器中,尝试设置:

onPanResponderTerminationRequest: () => false
Run Code Online (Sandbox Code Playgroud)


ris*_*k13 7

@IlyaDoroshin和@David Nathan的答案为我指明了正确的方向,但是我必须在滚动视图中将每个项目包装为可触摸的,而不是所有内容都可触摸的。

<ScrollView>
  ...
  <ScrollView horizontal>
    {items.map(item => (
        <TouchableWithoutFeedback>
          { /* your scrollable content goes here */ }
        </TouchableWithoutFeedback>
    ))}
  </ScrollView>
</ScrollView>
Run Code Online (Sandbox Code Playgroud)


Ily*_*hin 6

在 android 上为我修复了嵌套 ScrollView 的可滚动内容:

<ScrollView>
  ...
  <ScrollView horizontal>
    <TouchableWithoutFeedback>
      { /* your scrollable content goes here */ }
    </TouchableWithoutFeedback>
  </ScrollView>
</ScrollView>
Run Code Online (Sandbox Code Playgroud)


Shu*_* He 5

修改node_modules/react-native/Libraries/Components/ScrollResponder.js:第136行(参见更新):

scrollResponderHandleScrollShouldSetResponder: function(): boolean {
    return this.state.isTouching;
},
Run Code Online (Sandbox Code Playgroud)

更新:我发现滚动视图当前是否为动画并希望成为响应者,然后它将拒绝.ScrollResponder.js中的第189行.所以我修改了340行,它对我有用:

scrollResponderIsAnimating: function(): boolean {
  // var now = Date.now();
  // var timeSinceLastMomentumScrollEnd = now - this.state.lastMomentumScrollEndTime;
  // var isAnimating = timeSinceLastMomentumScrollEnd < IS_ANIMATING_TOUCH_START_THRESHOLD_MS ||
  //   this.state.lastMomentumScrollEndTime < this.state.lastMomentumScrollBeginTime;
  // return isAnimating;
    return false;
},
Run Code Online (Sandbox Code Playgroud)

你可以在这里看到:https://github.com/facebook/react-native/issues/41