ios 天然React:panResponder内部的滚动视图

to94eoyn  于 2023-03-05  发布在  iOS
关注(0)|答案(8)|浏览(176)

我在PanResponder里面使用了ScrollView。在Android上它工作正常,但在iOS上ScrollView不会滚动。我做了一些调查,这里有一些事实:
1.如果我在PanResponder.onMoveShouldSetPanResponder()中放置了一个断点,在我跨过去之前,scrollView将正常滚动,但一旦我释放断点,scrollView将停止工作。
1.如果我修改ScrollResponder.js,并在scrollResponderHandleStartShouldSetResponderCapture()中返回true-它通常在运行时返回false;并在scrollResponderHandleTerminationRequest()中返回false,scrollView工作正常,但当然,由于它吞下了事件,外部PanResponder将不会获得事件。
所以问题是:
1.我想让滚动视图工作,而不是吞掉事件。有人知道方法吗?
1.React系统如何在iOS上工作?ReactReact Native 系统文档没有向我解释。

aurhwmvo

aurhwmvo1#

若要在ScrollView(该视图是具有PanResponder的父组件的子组件)中启用滚动,必须确保ScrollView是其内部任何手势的响应者。默认情况下,手势事件从最深的组件向上冒泡到父组件。若要通过ScrollView捕获事件,可以添加内部具有PanResponder的视图。请参见(伪)示例,其中ChildComponent是PanResponder父项的子项。

const ChildComponent = ({ theme }) => {
    const panResponder = React.useRef(
        PanResponder.create({
            // Ask to be the responder:
            onStartShouldSetPanResponder: (evt, gestureState) => true,
            onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
        })
    ).current;

    return (
        <ScrollView style={{ height: 500 }}>
            <View {...panResponder.panHandlers}>
                ...
            </View>
        </ScrollView>
    );
};
oxosxuxt

oxosxuxt2#

PanResponder中有一个返回当前触摸位置的事件。您可以使用它来比较2个值以执行滚动。

wxclj1h5

wxclj1h53#

最后,我通过将scrollview封装在视图中,并将scrollview的样式设置为有限的高度来解决这个问题。

import * as React from 'react';
import { Text, View, StyleSheet,PanResponder,Animated,ScrollView,Dimensions} from 'react-native';
import { Constants } from 'expo';

const WINDOW_WIDTH = Dimensions.get("window").width;
const WINDOW_HEIGHT = Dimensions.get("window").height;
// You can import from local files

export default class App extends React.Component {
  constructor(props){
    super(props);
    this.minTop = 100;
    this.maxTop = 500;
    this.state={
      AnimatedTop:new Animated.Value(0),
    }
  }

  componentWillMount(){
    let that = this;
    this._previousTop = 100;
    this._panResponder = PanResponder.create({
      onMoveShouldSetPanResponder(){
        return true;
      },
      onPanResponderGrant(){
        that._previousTop = that.state.AnimatedTop.__getValue();
        return true;
      },
      onPanResponderMove(evt,gestureState){
        let currentTop = that._previousTop + gestureState.dy;
        that.state.AnimatedTop.setValue(that._previousTop+gestureState.dy);

      },
      onPanResponderRelease(){

      }
    })
  }

  render() {
    return (
      <View style={styles.container}>
        <Animated.View
          style={[styles.overlay,{top:this.state.AnimatedTop}]}
          {...this._panResponder.panHandlers}
        >
          <View style={{height:200,backgroundColor:"black"}}></View>
          <View>
            <ScrollView
              style={{height:500}}
            >
              <View style={{backgroundColor:"blue",height:200}}></View>
              <View style={{backgroundColor:"yellow",height:200}}></View>
              <View style={{backgroundColor:"pink",height:200}}></View>
              <View style={{backgroundColor:"red",height:200}}></View>
            </ScrollView>
          </View>
        </Animated.View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
  overlay:{
    position:"absolute",
    width:WINDOW_WIDTH,
    height:WINDOW_HEIGHT-100,
  }
});

我花了大量的时间来解决这个问题。希望这能帮助那些对同样问题感到困惑的人。

oipij1gg

oipij1gg4#

我不知道它现在是否有用,但你可以添加这行,

return !(gestureState.dx === 0 && gestureState.dy === 0)

在PanResponder的“onMoveShouldSetPanResponder”属性中,将evt和gestureState作为参数。
您的PanResponder应如下所示:

this._panResponder = PanResponder.create({
  onMoveShouldSetPanResponder(evt, gestureState){
    return !(gestureState.dx === 0 && gestureState.dy === 0)
  },
  onPanResponderGrant(){
    that._previousTop = that.state.AnimatedTop.__getValue();
    return true;
  },
  onPanResponderMove(evt,gestureState){
    let currentTop = that._previousTop + gestureState.dy;
    that.state.AnimatedTop.setValue(that._previousTop+gestureState.dy);

  },
  onPanResponderRelease(){

  }
})
rekjcdws

rekjcdws5#

我已经通过向ScrollView的所有内容添加onPress处理程序解决了这个问题-不管处理程序是否为no-op,滚动视图仍然可以正常工作。

dxpyg8gm

dxpyg8gm6#

如果你给予它一些缓冲,它就会起作用。

onMoveShouldSetPanResponderCapture: (evt, gestureState) => {
    // Only captures swipe downs
    return gestureState.dy > 0.05 * height; // don't move until it moves 5% of the height of screen; method that works when doing a
},

在这种情况下,即使您的PanResponder中有ScrollView或Flatlist,它也能正常工作。

qeeaahzv

qeeaahzv7#

我不知道你是否还需要这个,但我也会帮助别人的
如果你把panResponder放在ScrollView的一个兄弟视图上,ScrollView就会正常工作,然后你就可以定位那个兄弟视图了
以下是解决方法的example

kqqjbcuj

kqqjbcuj8#

我解决了这个问题

onMoveShouldSetPanResponder: (event, gesture) => {
  if (gesture?.moveX > gesture?.moveY) {
    return false;
  }
  return true;
},

在我的情况下,我有一个水平的平面列表在一个泛应答器内...

相关问题