PanResponder详解和踩到的坑以及解决办法和总结,

1347 查看

背景

前段时间开发版本迭代的时候有一个下拉刷新的功能,RN自带了一个下拉刷新RefreshControl,但是用户体验上有所欠缺,它的实现原理是下拉到一定距离之后会触发onRefresh()方法,一般我们是在这个方法中去获取fetch回来的状态来改变refreshing的值,这样大致上就能实现一个基本的下拉刷新,有一个问题是下拉保持触摸状态,没有释放,还是会执行上述的操作,这样就有点奇怪了,良好的用户体验是用户释放之后才会去触发onRefresh(),然后fetch,然后改变refreshing完成这一个下拉刷新的动作,作为一个正常的开发者,这个问题肯定要解决的,第一个思路就是到github(程序员的后花园,惊喜),上去找有没有适合的组件,推荐俩个组件:

下拉刷新下拉刷新1,将这俩个组件用在了业务场景中,发现有点水土不服,那怎么搞,自己写呗,然后就用到了今天的男猪脚PanResponder,然后就实现了业务需求,欢欢喜喜的上线了,然后就发现了一个坑,下面会先介绍PanResponder的用法,然后再说这个坑是什么,然后总结。

PanResponder

谷歌翻译了下,并没有这个词,可能是合成词,Responder是响应者,这个API就是用来响应用户触摸事件。对于RN,除了Text,其他组件都不能成为响应者,RN提供了几个能直接处理响应事件的组件,TouchableHighlight,TouchableNativeFeedback,TouchableOpacity,ToucnableWithoutFeedback,这四个触摸组件基本能够完成大多数的触摸事件,有四个回调方法,(注明一下:本小段内容参考于React Native 触摸事件处理详解

onPressIn:点击开始;onpressOut:点击结束或者离开;onPress:单击事件回调,用得比较多的方法就是这个了;onLongPress:长按事件回调;

那如果不使用上述方法,我自己就想成为触摸响应者,就是这么任性,RN也有办法实现你这个任性的需求,不过呢,你首先要申请成为触摸事件的响应者,触摸事件的处理周期是从用户手指按下屏幕,到用户手指抬起,就是一次完整的触摸操作了,没图说什么jj,上一张内涵图:



触摸生命周期

可以从上图中看到,一个组件可以成为触摸响应者,释放之后,就不是触摸响应者了,所以一个组件有倆种身份-男人与女人(非事件响应者和事件响应者)

非事件响应者

组件自己是不能直接响应触摸事件的,需要向RN提交申请,向RN表示我组件愿意响应触摸事件,有俩个属性

onStartShouldSetResponder:在触摸开始的时候,这个属性接收一个回调函数,bool型,返回true,表示愿意成为响应者

onMoveShouldSetResponder: 这个组件是在触摸进行的过程中,表示愿不愿意成为响应者,这次遇到的坑就是这个属性,在6s+上表现就是一dog shit,后面会详细的说明这个坑;

但是通常一个视图中是由多个组件拼装而成,组件之间还存在嵌套,每个组件都申请成为响应者,那到底用户触摸的时候我的响应组件应该选择哪个,所以RN还有俩个回调来告诉谁申请到了,为什么他可以申请到,因为给的钱多,优先级高。

onResponderGrant:表示申请成功,你成为了事件的响应者,这个时候开始,组件就进入了激活状态。

onResponderReject:表示申请失败,意味着其他组件正在进行事件处理,并且那个优先级高的人不想放弃事件处理,你只能等着,所以RN对这一套都有很好的设计。

事件响应者

如果你通过了申请,那么恭喜你进入了上层社会,成为了响应者,这个时候你就又拥有了几个技能,可以来获取用户到底触发了什么动作,

onRespinderStart:表示手指按下时,成功申请为事件响应者的回调。

onResponderMove:就是我手指按住然后一直拖啊拖,这里可以拿很多数据来做一些有意思的事情。

onResponderRelease:这个就是用户触摸事件完成了,释放了他的金手指,解放了屏幕,这以后,组件不再是事件响应者,组件取消激活。

onResponderEnd: game over,结束了事件响应的回调。

上面说到,一个视图会包含很多组件,上面的是针对孤家寡人而言的,那我是成群结队的又是什么逻辑呢,不要急,容我点根烟,再娓娓道来。

比如说俩层组件,我在外层申请到了成为响应者,那到底是父组件成为响应者,还是儿子组件继承父组件的财产呢。RN默认情况下使用冒泡机制,不是很明白的看这里,事件冒泡和事件委托,这么说呢,那就是儿子会成为响应者,展现了深沉的父爱,儿子先吃,你吃不完,给老爸。这样都能保证这一个嵌套组件都能得到响应,但是有时候父亲要先为儿子试一下,才能放心给儿子,有俩个回调,

onStartShouldSetResponderCapture(bool):capture(夺得,捕捉,捕获),返回true,表示父组件会劫持这个响应事件,自己成为响应者,

onMoveShouldSetResponderCapture:有没有发现,有start就伴随着Move,就像getter和setter一样,这个呢就是在滑动过程中问父组件要不要劫持。

上图:


事件处理流程

基本上就介绍这么多,上一个写得比较好的例子,http://browniefed.com/blog/react-native-animated-api-with-panresponder/,好像要翻墙的,翻墙看世界,我朋友说的。

刚开始实现下拉刷新的功能是直接使用下拉刷新控制器,提供了一个onRefresh(),下拉到一定的距离就会触发,当时去翻了下源码,好像是没看到,可能没看仔细,还有一个refreshing的状态,用来控制是否呈现菊花,就只使用RefreshControl 也能实现下拉刷新的功能,但是不好看,作为一个颜值与智慧并存的前端,当然不能忍,这个如果忍了,那么你就会继续忍受更多,那么就呵呵了,

然后实现逻辑是这样的,设置一个状态,isRelease,是否释放,isReresh,是否呈现菊花,这里把isRefresh放到了state中,isRelease只是作为一个变量,不要把和呈现无关的变量放到state中,然后,当触发了onRefresh()的时候,在onResponderRelease中判断用户是否释放了,只有触发并且释放,才会去fetch,然后回调改变isRefresh的值,接着出发视图的改变,写完这个逻辑,尝试一波,哎哟,不错哦,然后再测试几波,发现了一个问题。可能有的人发现了,我下拉很快,然后释放很快,onRefresh()和onResponderRelease()同时执行,当我释放的时候onRefresh()还没执行完,isRefresh的值没有改变,那么就不能达成那个 &&条件,到这里的时候,这个思想应该是对的,只需要在onRefresh() 的时候再调用一下onResponderRelease()就可以,



这些方法都可以在this._panResponder 这个对象集合中拿到,然后我就先 setState 然后 再跟着通过这个对象调了一下onResponderRelease()方法,这样貌似看上去可以,在真机上跑一波,what fuck,不行;仔细看了下代码,查了下文档,没有思路,然后问了下同事,setState是异步调用的,这样就完美解决了,先等setState执行完,回调一下就ok了,这个问题按照正常的流程应该就完了,但是就在前几天,台风袭击了厦门,改变了自然轨迹。

有反馈说在6s上点击列表点击不了,进不到详情页,第一反应,可能是最近的ios10系统的问题,然后我就借了2个6s 分别是10.0.1 和 9.3.5的问题,发现都存在上面的情况,再借了俩个6分别是10,9.3.5的系统没有表现,一切正常,借手机都是分分钟,要感谢土豪同事,有个缺点是现在在开发安卓,想找个正常点的安卓机都难;然后发现不是系统问题,是手机问题,我发现了一个共同点,列表页都点击不了,当时宝宝心里捉急啊,但是要表现淡定一下,遇到问题不要影响思考,列表页共用一个组件,组件用了Panresponder,然后我就去在google中 搜索 Panresponder 6s,出来的结果有点无语,但是也是开心的,因为定位到了问题,上链接,,在github上标题是这样的 "PanResponder blocking child Touchable on 6s and 6splus",我的天,然后就把这个问题解决了,测试通过,这时候如果有单元测试会不会更好一些,最近组里在推Jest,最后就用热更新把这个问题修复掉了,关于 热更新,可以看我处男作;上一个链接,工程师文化,其中有段话很好的形容了这次事情,





对于RN这种还没有一个正式版的工具,现在也只是到了0.33,我们需要关注它的版本迭代内容,还有当你要去使用一个api的时候,请一定要把这个api 哢明白了,才去使用。

吹b时刻

最近一部电影火爆了各大社区,诸如草榴之类的,开玩笑,哈哈,知乎,简书,尤其是豆瓣,那就是釜山行,告诉你这三个字是可以点击的,不会把你带到那种网站的,为什么要说这件事情呢,因为我常在豆瓣上逛,很早就知道了这部电影,苦于找寻不到资源,前段时间和朋友一起吃饭,先描述一下我朋友,他是一个好人,对的,是一个好人,还是老实孩子,他说出了“翻墙看世界”的金句,那天就和他讨论这部电影了,然后就和我说A站上有,我听到A站,what?,没听错吧,A站上会有? 就算有,我也不屑于去看,我是一个正直的人,其实是自从苍老师退役之后,在我看来,从此天下无片(我真是一个正直的人),然后后来他告诉我,这是正常视频网站,想什么呢。原来我误会他了,但是他又教我忍者道义(javascript 忍者秘籍,推荐) ,把你要google的东西先翻译成英文,你会看到更多的世界,亲测可行,老司机啊,带带我。吹完了b,这部电影还是不错的,值得看看,看完觉得不过瘾,再推荐一部日本电影“告白”。



团队合作


还有一大堆砖等着我和我的搭档要搬呢................