https://goo.gl/zcHLJc/LwisMQ

React Native 五:手势
一、Touchable手势
1.React Native提供了4个来做这个事情,具体如下:
TouchableHighlight:高亮触摸,用户点击时,会产生高亮效果;
TouchableNativeFeedback:
TouchableOpacity:透明触摸,用户点击时,点击的组件不会出现任何视觉变化;
TouchableWithoutFeedback:无反馈触摸,用户点击时,点击的组件不会有任何视觉变化;
2.这4个组件,我们可以应用某个部分绑定上Touch事件,并支持一下方法:
onPressIn:
onPressOut:
onLongPress:
3.下面我们以实例演示下,相关代码实现:
Index.android.js文件:
import React, {
TouchableHighlight,
} from 'react-native';
class AwesomeProject extends Component {
show(text) {
alert(text);
//手势相关事件的实现
onPressIn(){
this.start = Date.now()
console.log(&press in&)
onPressOut(){
console.log(&press out&)
onPress(text){
console.log(&press&)
alert(text);
onLonePress(){
AppRegistry,
console.log(&long press &+(Date.now()-this.start))
render() {
//TouchableHighlight包裹绑定Touch手势的组件,并实现支持的4个事件
var styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
width: 200,
height: 200,
borderRadius: 100,
backgroundColor: 'red'
touchable: {
borderRadius: 100
AppRegistry.registerComponent('AwesomeProject', () =& AwesomeProject);
4.点击,我们看见具体的运行效果如下:
5.我们使用Debug模式,研究下4个手势出现的条件和顺序;
摇晃手机,选择Debug JS;
打开Chrome,在弹出的Debug页面http://localhost:8081/debugger-ui后,选择开发着工具,点击手机上的按钮就可以看见浏览器控制台的
输出内容PressIn-&longPress-&pressOut;
二、手势响应生命周期
1.对于大部分应用,使用以上4个Touch*组件,在配合4个Press事件就能对用户的手势进行响应。但是对于比较复杂的交互,还得使用手势响应;
2.响应手势的基本单位是responder,具体来说就是View组件,任何View组件都是潜在的responder;
3.一个普通的View组件成为能响应手势操作的responder,只要设置几个手响应生命周期的方法即可,具体如下:
View.props.onStartShouldSetResponder:用户开始触摸屏幕的时候,是否愿意成为响应者;
View.props.onMoveShouldSetResponder:在每一个触摸点开始移动的时候,再询问一次是否响应触摸交互;
View.props.onResponderGrant:要开始响应触摸事件了;
View.props.onResponderReject:响应者现在另有其人,而且暂时不会放权,另作安排;
View.props.onResponderMove:用户正在屏幕上移动手指;
View.props.onResponderRelease:触摸操作结束收触发;
View.props.onResponderTerminationRequest:有其它组件请求接替响应者,当前View是否放权;
View.props.onResponderTerminate:响应权已经交出;
4.一个React Native应用中同时之能存在一个responder,具体响应步骤如下:
用户通过触摸或者滑动来&激活&某个responder,View.props.onStartShouldSetResponder以及View.props.onMoveShouldSetResponder这两个方法处理,如果返回true,则这个View能够响应触摸或者滑动手势被激活;
如果组件被激活,View.props.onResponderGrant方法被调用,一般这个时候去改变组建的底色或者透明度,表示组件已经被激活;
接下来,用户开始滑动手指,此时View.props.onResponderMove方法被调用;
当用户的手指离开屏幕之后,View.props.onResponderRelease方法被调用,组件恢复被触摸之前样式,例如底色和透明度恢复之前的样式,完成一次手势操作;
正常流程:响应touch或者move手势 -& grant(被激活) -& move -& release(结束事件);
5.下面我们以实例演示下,相关代码如下:
index.android.js文件
import React, {
} from 'react-native';
var AwesomeProject = React.createClass({
getInitialState(){
bg: 'white'
componentWillMount(){
this._gestureHandlers = {
onStartShouldSetResponder: () =& true,
onMoveShouldSetResponder: ()=& true,
onResponderGrant: ()=&{
this.setState({bg: 'red'})
onResponderMove: ()=&{
console.log(123)
onResponderRelease: ()=&{
this.setState({bg: 'white'})
render() {
var styles = StyleSheet.create({
AppRegistry.registerComponent('AwesomeProject', () =& AwesomeProject);
6.运行效果如下,onClick为未点击,Click为点击,后面为控制台输出log:
注意:如果运行Demode的时候错误提示如下图:
使用var AwesomeProject = React.createClass();的方式创建组件;
三、手势事件传递
1.onStartShouldSetResponder于onMoveShouldSetResponder是以冒泡的形式调用的,即嵌套最深的节点最先调用;
2.意味着多个View同时在ShouldSetResponder中返回true时,最底层的View将优先&夺权&;
3.但是有些时候,某个父View会希望先能成为响应者,我们可以利用&捕获期&来解决。响应系统从最底层的组件开始冒泡前,会首先执行一个&捕获期&,在此期间会触发on*ShouldSetResponderCapture系列事件。因此,如果某个父View想要在触摸开始时阻止组件成为响应者,那就应该处理onStartShouldSetResponderCapture事件冰返回true值;
View.props.onStartShouldSetResponderCapture:(evt)=&true;
View.props.onMoveShouldSetReponderCapture(evt)=&ture;
4.下面我们将以实例演示一下,实现代码如下:
Index.android.js文件:
import React, {
} from 'react-native';
var AwesomeProject = React.createClass({
getInitialState(){
bg: 'white',
bg2: 'white'
componentWillMount(){
this._gestureHandlers = {
//外部正方形在&捕获期&阻止底层时间成为响应者
onStartShouldSetResponderCapture: () =& true,
onMoveShouldSetResponderCapture: ()=& true,
onResponderGrant: ()=&{this.setState({bg: 'red'})},
onResponderMove: ()=&{console.log(123)},
onResponderRelease: ()=&{this.setState({bg: 'white'})},
this._gestureHandlers2 = {
//内部正方形在即时实现了on*ShouldSetResponder也无法成为响应者
onStartShouldSetResponder: () =& true,
onMoveShouldSetResponder: ()=& true,
onResponderGrant: ()=&{this.setState({bg2: 'green'})},
onResponderMove: ()=&{console.log(123)},
onResponderRelease: ()=&{this.setState({bg2: 'white'})}
render: function() {
var styles = StyleSheet.create({
AppRegistry.registerComponent('AwesomeProject', () =& AwesomeProject);
5.运行效果如下图,点击内部正方形,外部正方形相应事件:
四、evt参数
1.和Web开发中的事件参数类似,以上的每个方法都有一个evt参数,在事件发生的过程中,这个evt参数的nativeEvent属性的各个指能表示手势的状态:
nativeEventchangedTouches:在上一次事件之后,所有发生变化的触摸事件的数组集合(即上一次事件后,所有移动过的触摸点)
identifier:触摸点的ID
locationX:触摸点相对于父元素的横坐标
locationY:触摸点相对于父元素的纵坐标
pageX:触摸点相对于根元素的横坐标
pageY:触摸点相对于根元素的纵坐标
target:触摸点所在的元素ID
timestamp:触摸事件的时间戳,可用于移动速度的计算
touches:当前屏幕上的所有触摸点的集合
五、PanResponder
1.除了手势相应系统之外,React Native还抽象出一套PanResponder方法,它的抽象成程度更高,使用起来更为方便;
2.使用PanResponder的时候,相应手势的逻辑和流程都不变,只需要根据文档对几个方法名称参数修改即可:
第一个参数evt;
第二个gestureState,包含手势进行过程中更多信息,比较常见如下:
dx/dy:手势进行到现在的横向/纵向相对位移;
vx/vy:此刻的横向/纵向速度;
numberActiveTouches:reponder上的触摸的个数;
3.下面我们就使用PanResponder实现拖拽效果,代码实现如下:
index.android.js文件:
import React, {
PanResponder,
} from 'react-native';
var AwesomeProject = React.createClass({
getInitialState(){
bg: 'white',
componentWillMount(){
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: () =& true,
onMoveShouldSetPanResponder: ()=& 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: 'white',
top: this._top+gs.dy,
left: this._left+gs.dx
render: function() {
//设置手势事件处理对象
var styles = StyleSheet.create({
container: {
//开始的矩形位于中间,下图拖动到下部区域
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
AppRegistry.registerComponent('AwesomeProject', () =& AwesomeProject);
4.运行演示如下,由于只能上传图片,无法演示动画,样式中矩形位于中间,图中拖动至下方:

我要回帖

更多关于 goo.gl/zcHLJc 的文章

 

随机推荐