RN手势响应系统总结

2019-06-05  本文已影响0人  注定暂时漂泊xxx

响应者的生命周期

生命周期方法列表

View.props.onStartShouldSetResponderCapture: (evt) => true 
View.props.onMoveShouldSetResponderCapture: (evt) => true
View.props.onStartShouldSetResponder: (evt) => true
View.props.onMoveShouldSetResponder: (evt) => true
View.props.onResponderGrant: (evt) => {}
View.props.onResponderReject: (evt) => {}
View.props.onResponderMove: (evt) => {}
View.props.onResponderRelease: (evt) => {}
View.props.onResponderTerminationRequest: (evt) => true
View.props.onResponderTerminate: (evt) => {}

evt是一个合成事件,它包含以下结构:

生命周期方法详解

捕获 ShouldSet 事件处理

“是否愿意成为响应者”系列方法:onStartShouldSetResponder与onMoveShouldSetResponder是以冒泡的形式调用的,即嵌套最深的节点最先调用。这意味着当多个 View 同时在*ShouldSetResponder中返回 true 时,最底层的 View 将优先“夺权”。在多数情况下这并没有什么问题,因为这样可以确保所有控件和按钮是可用的。

但是有些时候,某个父 View 会希望能先成为响应者。我们可以利用“捕获期”来解决这一需求。响应系统在从最底层的组件开始冒泡之前,会首先执行一个“捕获期”,在此期间会触发on*ShouldSetResponderCapture系列事件。因此,如果某个父 View 想要在触摸操作开始时阻止子组件成为响应者,那就应该处理onStartShouldSetResponderCapture事件并返回 true 值。

是否愿意成为响应者

尝试成为响应者

开始响应触摸事件

封装手势

可以认为是对手势响应生命周期方法的模板封装,与gesture responder system 比起来,封装手势方法的抽象程度更高,使用起来也更加方便

PanResponder

响应事件

事件方法列表
  1. onMoveShouldSetPanResponder: (evt, gestureState) => {...}
  2. onMoveShouldSetPanResponderCapture: (evt, gestureState) => {...}
  3. onStartShouldSetPanResponder: (evt, gestureState) => {...}
  4. onStartShouldSetPanResponderCapture: (evt, gestureState) => {...}
  5. onPanResponderReject: (evt, gestureState) => {...}
  6. onPanResponderGrant: (evt, gestureState) => {...}
  7. onPanResponderStart: (evt, gestureState) => {...}
  8. onPanResponderEnd: (evt, gestureState) => {...}
  9. onPanResponderRelease: (evt, gestureState) => {...} //用户手指离开屏幕时,调用该方法
  10. onPanResponderMove: (evt, gestureState) => {...} //用户滑动手指时,调用该方法
  11. onPanResponderTerminate: (evt, gestureState) => {...}
  12. onPanResponderTerminationRequest: (evt, gestureState) => {...}
  13. onShouldBlockNativeResponder: (evt, gestureState) => {...}
说明:

基本用法

  componentWillMount: function() {
    this._panResponder = PanResponder.create({
      // 要求成为响应者:
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,

      onPanResponderGrant: (evt, gestureState) => {
        // 开始手势操作。给用户一些视觉反馈,让他们知道发生了什么事情!

        // gestureState.{x,y} 现在会被设置为0
      },
      onPanResponderMove: (evt, gestureState) => {
        // 最近一次的移动距离为gestureState.move{X,Y}

        // 从成为响应者开始时的累计手势移动距离为gestureState.d{x,y}
      },
      onPanResponderTerminationRequest: (evt, gestureState) => true,
      onPanResponderRelease: (evt, gestureState) => {
        // 用户放开了所有的触摸点,且此时视图已经成为了响应者。
        // 一般来说这意味着一个手势操作已经成功完成。
      },
      onPanResponderTerminate: (evt, gestureState) => {
        // 另一个组件已经成为了新的响应者,所以当前手势将被取消。
      },
      onShouldBlockNativeResponder: (evt, gestureState) => {
        // 返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者
        // 默认返回true。目前暂时只支持android。
        return true;
      },
    });
  },

  render: function() {
    return (
      <View {...this._panResponder.panHandlers} />
    );
  },
示例:
import {
    View,
    StyleSheet,
    PanResponder
} from 'react-native';

class QQAndGameHome extends PureComponent {
    static contextTypes = {
        router: PropTypes.object,
        store: PropTypes.object
    }

    constructor(props) {
        super(props);
        this.state = {
            top: JDDevice.getRpx(100),
            left: JDDevice.getRpx(100),
            bg: 'gray',
        };

        this.panResponder = PanResponder.create({
            onStartShouldSetPanResponder: () => true,
            onMoveShouldSetPanResponderCapture: () => true,
            onPanResponderGrant: () => {
                this._top = this.state.top;
                this._left = this.state.left;
                this.setState({bg: 'red'});
            },
            onPanResponderMove: (evt, gs) => {
                console.log(gs.dx+' '+gs.dy);
                this.setState({
                    top: this._top+gs.dy,
                    left: this._left+gs.dx
                });
            },

            onPanResponderRelease: (evt, gs)=>{
                this.setState({
                    bg: 'gray',
                    top: this._top+gs.dy,
                    left: this._left+gs.dx
                })
            }

        });
    }
    
    render() {
        return(
            <View
                {...this.panResponder.panHandlers}
                style={[myStyles.rect,{
                    "backgroundColor": this.state.bg,
                    "top": this.state.top,
                    "left": this.state.left
                    }]}
            >
            ...
            </View>
        )
    }
    
}


const myStyles = StyleSheet.create({
    rect: {
        position: 'absolute',
        width: JDDevice.getRpx(100),
        height: JDDevice.getRpx(100),
        borderColor: 'black'
    }
});

TouchableHighlight 与 Touchable 系列组件

响应系统用起来可能比较复杂。所以我们提供了一个抽象的Touchable实现,用来做“可触控”的组件。

TouchableHighlight

TouchableOpacity

TouchableWithoutFeedback

TouchableNativeFeedback

上一篇 下一篇

猜你喜欢

热点阅读