-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
“指尖上的魔法” -- 谈谈React-Native中的手势 #1
Comments
赞
|
非常棒 |
后面将要被激活的 responder 去和前面还没有被释放的 responder “协商”:兄弟,你都被激活这么久了,让我也活动一下呗?结果两种情况: 前面一种情况,后面的 responder 的 onResponderReject 方法被调用,后面的 responder 没有被激活 这里如果按照读者阅读习惯,是不是弄反了?“强硬情况下”后面的 responder 的 onResponderReject 方法会被调用吧? |
@qddegtya 确实写反了,谢谢纠正 :) |
@jabez128 感谢前辈的深度好文! |
点赞 |
@jabez128 关于滑动事件的冒泡还不是很明白,自己在安卓下测试,如果在里面框框滑动的话,发现外层框框的 onMoveShouldSetResponder 和 onResponderMove 会被执行。 |
有判断手势 上滑下滑的例子吗 |
@jabez128 2016年再来看,代码方面有些问题,特别是 比如说
|
很久没有看到这么简洁易懂清晰明了的文章了! |
有一个问题,请问下滑动一半的时候滑到外面了在松手,那么release方法就不会执行了,他会执行其他什么方法吗 |
感谢 |
请教下,如果有多个元素可以被拖拽,如何识别是拖拽的哪个元素呢?能给handler传参数么? |
感谢,收藏了 |
感谢,非常不错。 |
如何可以直接在native层面知道 这个RCTView是否可以点击? |
感谢分享! 我的代码是这样的,用一张图片image当作一个按钮TouchableOpacity,这个按钮是可以拖拽的(app首页中常见的那种图片小按钮) 图片是可以拖拽的,但是没有了点击的效果;然后我发现点击的区域永远是在top=0,left=0的位置上。 请问,该如何解决拖拽一个按钮呢?感谢 -----add------- |
mark!!! Thanks a lot |
@huangxiaohao |
React-Native是一款由Facebook开发并开源的框架,主要卖点是使用JavaScript编写原生的移动应用。从2015年3月份开源到现在,已经差不多有半年。目前,React-Native正在以几乎每周一个版本的速度进行快速迭代,开源社区非常活跃。2015年9月15日,React-Native正式宣布支持安卓,并在项目主页中更新了相关文档,这意味着React-Native已经完全覆盖了目前主流的iOS和Android系统,做到了“learn once,write everywhere”。React-Native能否颠覆传统的APP开发方式,现在下结论还为时尚早,但从微博和Twitter对React-Native相关消息的转发数量和评论来看,React-Native在未来的一段时间内都将是移动开发的热点。
从我自己的实际使用经历出发,在使用React-Native写了几个Demo之后,我觉得React-Native是一个非常有前途的框架。虽然目前文档并不能做到面面俱到,实际使用过程中坑也略多,但是填坑的速度也非常快。在项目的issues中提一个issue,基本都能在几个小时之内获得解答或者解决方案。因此,我决定比较系统的学习一下React-Native。
在移动应用开发中,手势是不可忽视的一个重要组成部分,React-Native针对应用中的手势处理,提供了gesture responder system,从最基本的点击手势,到复杂的滑动,都有现成的解决方案。
和以往的Hybrid应用相比,使用React-Native开发的原生应用的一大优势就是可以流畅的响应用户的手势操作,这也是使用React-Native相比以往在原生应用中插入webview控件的一个优势,因此,相比web端的手势,React-Native应用中的手势要复杂得多。我在初次接触React-Native手势之初也是看的一头雾水,经过搜索也发现相关的资料比较少,因此萌发了写一篇相关文章的想法。这也是写作本文的初衷,一方面总结自己学习和摸索的经验,以作为后来使用中的备忘录,另一方面也作为交流分享之用。
Touch*手势
移动应用中最简单的手势,就是touch手势,而这也是应用中最常使用的手势,类比web开发中的事件,就好比web开发中的click。在web开发中,浏览器内部实现了click事件,我们可以通过
onclick
或者addEventListener('click',callback)
来绑定click
事件。React-Native也针对Touch手势进行了类似的实现,在React-Native中,一共有四个和Touch相关的组件:使用这四个组件,我们就可以在应用的某个部分绑定上Touch事件,来个简单的例子:
在上面的代码中,主要部分就是一个作为容器的View,一个作为按钮的View,因为想要给这个按钮绑定Touch手势,因此使用了TouchableHighlight这个和Touch相关的组件,将它作为按钮的一个包裹,在这个包裹的props中规定相应的回调即可。
前面提到了和Touch相关的组件一共有四个,它们的基本用法都很类似,只是实现的功能不太相同。先说最常用的TouchableHighlight,这个组件的作用,除了给内部元素增加绑定事件之外,还负责给内部元素增加“点击态”。所谓的“点击态”,就是在用户在点击的时候,会产生一个短暂出现覆盖层,用来告诉用户这个区块被点击到了。TouchableNativeFeedback这个组件只能用在安卓上,它可以针对点击在点击区域中显示不同的效果,例如最新安卓系统中的Material Design的点击波纹效果。TouchableOpacity这个组件用来给为内部元素在点击时添加透明度。TouchableWithoutFeedback这个组件只响应touch手势,不增加点击态,不推荐使用。
四个组件的用法大致相同,具体的细节方法可以参看具体文档。回头看上面的代码,在iOS模拟器中运行的效果图如下:
在上面的代码中,TouchableHighlight组件上绑定了4个方法:
这4个方法也是React-Native帮助用户实现的4个手势,通过在4个相应的回调函数中输出不同的内容,我们可以研究4个手势出现的条件和顺序。打开chrome debug模式,点击模拟器中的按钮,可以看到浏览器控制台里面的输出内容:
原生应用之所以为原生,和web应用相比,有两个比较主要的区别:
前面一点比较清楚,第二点选择中途撤销是什么意思呢?举个最简单的例子,用微信聊天的时候,点击了一个好友,可以进入聊天界面,但是如果我点中了一个好友,突然又不想和他聊天了,我会多按一会,然后将手指划开,这样就可以撤销刚才的触摸事件,就好像根本就没有点击过一样。平时使用得太习惯,可能没有意识到原来这个操作是撤消了触摸事件,现在回过头一想,还真是这么一回事。
通过前面的实验,我们可以对press,pressIn,pressOut,longPress事件的触发条件和触发顺序有一个比较清晰的了解:
以上内容就是对React-Native对Touch事件的实现和用法分析,对于大部分应用来说,使用这四个Touch*组件再配合4个press事件就能对用户的手势进行响应。但是对于比较复杂的交互,还是得使用React-Native中的gesture responder system。
gesture responder system
在React Native中,响应手势的基本单位是
responder
,具体来说,就是最常见的View
组件。任何的View组件,都是潜在的responder,如果某个View组件没有响应手势操作,那是因为它还没有被“开发”。将一个普通的View组件开发成为一个能响应手势操作的responder,非常简单,只需要按照React Native的gesture responder system的规范,在props上设置几个方法即可。具体如下:
乍看之下,这几个方法名字又长有奇怪,但是当了解了React Native对手势响应的流程之后,记忆这几个方法也非常容易。
要理解React Native的手势操作过程,首先要记住一点:
正因为如此,gesture responder system中才存在_reject和_terminate方法。React Native事件响应的基本步骤如下:
综上所述,一次正常的手势操作的流程如下所示:
响应touch或者move手势 -> grant(被激活) -> move -> release(结束事件)
来段简单的示例代码:
运行这段代码,当中间的正方形被激活时,底色变为红色,release之后,底色又变为白色。
上面是正常事件响应流程,但是当应用中存在不止一个手势responder的时候,事情可能就复杂起来了。比如应用中存在两个responder,当使用一个手指激活一个responder之后,又去激活另一个responder会怎么样?因为React Native应用中只存在一个Responder,此时就会出现responder互斥的情况。具体来说过程如下:
上面的步骤中,比较重要的部分是第三步“协商”,这个步骤由onResponderTerminationRequest这个方法的返回值决定,如果一个responder的这个方法的返回值是true,那么说明这个responder是“好说话”的方法,反之则是“强硬”的方法。
由于在iOS simulator上不好模拟这个过程,大家可以自行编写应用在真机上对这个“协商”的步骤进行尝试。
和web的事件的冒泡过程类似,React Native中的事件遵循的也是冒泡机制。默认情况下,当潜在的responder的互相嵌套时,最顶部的responder将会响应事件。大部分时候,这也是开发者想要的逻辑。但是我们可以来自定义响应事件的responder。具体来说,通过:
两个方法来进行设置。当某个潜在responder的这两个方法的其中一个返回值为true时,即使当前的View组件不在最顶部,唯一一个responder的位置也会由它占据。看下面的例子:
这是正常的情况,当用户触摸最顶部的正方形时,最顶部的正方形会响应触摸事件,底色变为绿色,外层的正方形则不会响应触摸事件:
而当在外层的View中加入
两个方法之后,即使点击最顶部的小正方形,响应的responder也变为了外层的正方形:
和web开发中的事件参数类似,以上的每个方法都有一个evt参数,在事件发生的过程中,这个evt参数的nativeEvent属性的各个值能够标示手势进行的状态,如下所示:
参数的具体含义可以参看React Native文档。
PanResponder
除了gesture responder system之外,React Native还抽象出了一套PanResponder方法,和gesture responder system相比,PanResponder方法的抽象程度更高,使用起来也更为方便。在使用PanResponder的时候,相应手势的逻辑和流程都不变,只需要根据文档对几个方法名称作修改即可。PanResponder的好处是:对于每个方法,除了第一个evt参数之外,开发者还可以使用第二个参数gestureState,这个gestureState是一个对象,包含手势进行过程中更多的信息,其中比较常用的几个是:
通过使用PanResponder,我们可以非常方便的实现drag & drop的效果。代码如下所示:
总结
以上的内容就是我近一段事件来对React Native手势的学习和理解。讲了一些基本原理,但是要实现一些更加复杂的手势,例如pinch、rotate、zoom,还需要更进一步的研究和学习。
===============
The text was updated successfully, but these errors were encountered: