【React Native 系列教程之一】触摸事件的两种形式与四种Touchable组件详解

ytbf0203 8年前
   <p>本文是RN(React Native)系列教程第一篇,当然也要给自己的群做个广告:</p>    <p>React Native @Himi :126100395  刚创建的群,欢迎一起学习、讨论、进步。</p>    <p>本文主要讲解两点:</p>    <p>1.   PanResponder:触摸事件,用以获取用户手指所在屏幕的坐标(x,y)或触发、或滑动、或抬起几种事件通知。</p>    <p>2.   Touchable:React为我们封装好的触摸组件。引用原文:“响应系统用起来可能比较复杂。所以我们提供了一个抽象的 Touchable 实现,用来做“可触控”的组件。这一实现利用了响应系统,使得你可以简单地以声明的方式来配置触控处理。”</p>    <h2>一:触摸事件各事件响应与坐标获取</h2>    <p>1. 在import React 中添加要使用的触摸组件:</p>    <pre>  <code class="language-javascript">importReact, {    ...    PanResponder,//触摸必要的组件    ...  } from 'react-native';  </code></pre>    <p>2. 声明:</p>    <pre>  <code class="language-javascript">constructor(props) {   super(props);   this.state = {                eventName:'',        pos: '',   };      this.myPanResponder={}  }  </code></pre>    <p>这里先声明了两个变量posX,posY用于显示坐标用,另外声明了一个 myPanResponder 用于后面的触摸事件。</p>    <p>3. 创建、设置与响应</p>    <pre>  <code class="language-javascript">componentWillMount() {        this.myPanResponder = PanResponder.create({        //要求成为响应者:        onStartShouldSetPanResponder: (evt, gestureState) => true,        onStartShouldSetPanResponderCapture: (evt, gestureState) => true,        onMoveShouldSetPanResponder: (evt, gestureState) => true,        onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,        onPanResponderTerminationRequest: (evt, gestureState) => true,             //响应对应事件后的处理:        onPanResponderGrant: (evt, gestureState) => {          this.state.eventName='触摸开始';          this.forceUpdate();        },        onPanResponderMove: (evt, gestureState) => {          var _pos = 'x:' + gestureState.moveX + ',y:' + gestureState.moveY;          this.setState( {eventName:'移动',pos : _pos} );        },        onPanResponderRelease: (evt, gestureState) => {          this.setState( {eventName:'抬手'} );        },        onPanResponderTerminate: (evt, gestureState) => {          this.setState( {eventName:'另一个组件已经成为了新的响应者'} )        },      });    }  </code></pre>    <p>以上代码分为3部分,先创建,然后对需要追踪的事件进行设置响应,最后重写响应的事件进行处理即可。</p>    <p>需要注意的:绑定到componentDidMount的话可能会失效,需要在componentWillMount处预先创建手势响应器</p>    <p>4. 为要响应的View进行设置</p>    <pre>  <code class="language-javascript">{...this.myPanResponder.panHandlers}  </code></pre>    <p>5. 完善Render函数:</p>    <pre>  <code class="language-javascript">render() {      return (      <Viewstyle={styles.himiViewStyle}          {...this.myPanResponder.panHandlers}      >          <Text style={styles.himiTextStyle}>HimiReactNative 教程</Text>          <Viewstyle={styles.container}>            <Text style={styles.text}>{this.state.eventName}</Text>            <Text style={styles.text}>{this.state.pos}</Text>          </View>       </View>       )}  </code></pre>    <p>6.用到的布局和样式:</p>    <pre>  <code class="language-javascript">var styles = StyleSheet.create({    container: {      flex: 1,      flexDirection: 'row',      justifyContent: 'center',      alignItems: 'center',      backgroundColor: '#F5FCFF',    },    text: {      color:'#f00',      fontSize:30,    },    himiViewStyle:{      flex: 1,      flexDirection: 'column',      justifyContent: 'center',      alignItems: 'center',      backgroundColor: '#F5FCFF',    },    himiTextStyle:{      color:'#f00',      fontSize:30,      marginTop:70,    },  });  </code></pre>    <p>效果如下:(点击查看动态效果)</p>    <p><img src="https://simg.open-open.com/show/d293716a8b4565a26da57d4eb69e73fd.gif"></p>    <p>如上是第一种形式,下面我们简单说下如何使用第二种形式:</p>    <pre>  <code class="language-javascript">componentWillMount() {              this.myPanResponder = PanResponder.create({           //*********************第二种触摸的形式***************************        //类似 shouldComponentUpdate,监听手势开始按下的事件,返回一个boolean决定是否启用当前手势响应器        onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder.bind(this),           //监听手势移动的事件,返回一个boolean决定是否启用当前手势响应器        onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder.bind(this),           //手势开始处理        onPanResponderGrant: this._handlePanResponderGrant.bind(this),           //手势移动时的处理        onPanResponderMove: this._handlePanResponderMove.bind(this),           //用户放开所有触点时的处理        onPanResponderRelease: this._handlePanResponderRelease.bind(this),           //另一个组件成了手势响应器时(当前组件手势结束)的处理        onPanResponderTerminate: this._handlePanResponderEnd.bind(this)              });    }       _handleStartShouldSetPanResponder(e, gestureState) {      //返回一个boolean决定是否启用当前手势响应器      return true;    }     _handleMoveShouldSetPanResponder(e, gestureState) {      return true;    }    _handlePanResponderGrant(e, gestureState) {      this.setState({        eventName : 'Start'      })      }    _handlePanResponderRelease(e, gestureState) {      this.setState({        eventName : 'End'      })    }    _handlePanResponderMove(e, gestureState) {      var _pos = 'x:' + gestureState.moveX + ',y:' + gestureState.moveY;      this.setState({        eventName : 'Move:',        pos : _pos      })    }    _handlePanResponderEnd(e, gestureState) {      this.setState({        eventName : '另一个组件成了手势响应器时(当前组件触摸结束)的处理'      })    }  </code></pre>    <p>第二种形式就是将触摸响应绑定到我们自定义的函数,其他没有基本没区别。改动只有两点:</p>    <p>1. 绑定时修改成将触摸事件的回调绑定到我们自定义函数。</p>    <p>2. 添加每个响应的自定义函数。</p>    <p>效果如下:(点击查看动态效果)</p>    <p><img src="https://simg.open-open.com/show/1c91a83911db39e5c92272acd81b9667.gif"></p>    <h2>二:四种 Touchable 触摸组件     </h2>    <p>Touchable 一共有四种形式:</p>    <p>TouchableHighlight: 当按下的时候,封装的视图的不透明度会降低,同时会有一个底层的颜色透过而被用户看到,使得视图变暗或变亮。</p>    <p>TouchableNativeFeedback:(仅限Android平台) 在Android设备上,这个组件利用原生状态来渲染触摸的反馈。</p>    <p>TouchableOpacity: 当按下的时候,封装的视图的不透明度会降低。这个过程并不会真正改变视图层级,大部分情况下很容易添加到应用中而不会带来一些奇怪的副作用。</p>    <p>TouchableWithoutFeedback: 除非你有一个很好的理由,否则不要用这个组件。所有能够响应触屏操作的元素在触屏后都应该有一个视觉上的反馈(然而本组件没有任何视觉反馈),仍会触发触摸事件的响应</p>    <p>1. 添加Touchable的四种组件</p>    <pre>  <code class="language-javascript">importReact, {    ...    Image,    Alert,    TouchableHighlight,    TouchableNativeFeedback,    TouchableOpacity,    TouchableWithoutFeedback,    ...  } from 'react-native';  </code></pre>    <p>Himi这里还添加了Image和Alert两个组件:</p>    <p>Image 是图片组件,这里是为了测试效果,将Touchable发生在图片</p>    <p>Alert 弹窗提示组件,是为了通过弹窗,更好的展示出事件响应效果</p>    <p>2. 在Render添加如下:</p>    <pre>  <code class="language-javascript"><Viewstyle={styles.container}>          <TouchableHighlight            underlayColor='#4169e1'            onPress={this.test}              >               <Image               source={require('./res/himi.png')}               style={{width: 70, height: 70}}               />          </TouchableHighlight>             <TouchableOpacity            activeOpacity={0.5}                onPress={()=>{Alert.alert('Himi', ' TouchableOpacity ');} }              >               <Image               source={require('./res/himi.png')}               style={{width: 70, height: 70}}               />          </TouchableOpacity>             <TouchableWithoutFeedback            underlayColor='#4169e1'            activeOpacity={0.5}                onPress={()=>{Alert.alert('Himi', ' TouchableWithoutFeedback ');} }              >               <Image               source={require('./res/himi.png')}               style={{width: 70, height: 70}}               />          </TouchableWithoutFeedback>         </View>  </code></pre>    <p>由于Himi写博客时在Mac下,那么如下我们来创建除仅限Android的TouchableNativeFeedback之外的三种形式。</p>    <p>根据反馈的形式,大家可以自行设置其透明度、背景色、样式等。</p>    <p>效果图如下:(点击查看动态图)</p>    <p><img src="https://simg.open-open.com/show/b4ddaa637a243c5c4838836aa6116968.gif"></p>    <p> </p>    <p>来自: <a href="/misc/goto?guid=4959673712240875903" rel="nofollow">http://www.himigame.com/react-native/2203.html</a></p>    <p> </p>