1.背景
在文章例子中的RN(以下用RN表示React Native)版本是0.43.3。RN官方和非官方提供了很多左右滑动的控件和组件,作者使用的比较多的就是react-native-scrollable-tab-view和react-native-viewpager(之前作为一个Android开发者,对ViewPager情有独钟),它们在单独使用的时候并没有什么问题,使用的方法也很简单。但是在实际的开发中,比如主页面左右滑动切换Tab,同时子页面中又有左右切换轮播图的组件,这个时候就会有左右滑动冲突的问题,如果不加以处理的话,实际的效果体检就会很差。俗话说站在巨人的肩膀上看得远(其实是作者比较菜,能力有限),本文就是在这两个控件的基础上进行改进来解决这个问题。
http://www.jianshu.com/p/22d25be7782e
2.下载组件
接下来要用到的两个组件的Github地址分别为,
https://github.com/skv-headless/react-native-scrollable-tab-view
https://github.com/race604/react-native-viewpager
上面都有它们的介绍,相关Api以及如何使用的例子,在这里就不多加以介绍了,这里主要讲如何修改去解决活动冲突的问题
3.问题分析和解决思路
那么问题来了,该怎么去解决这个滑动冲突的问题呢?
如果开发过Android项目可能知道,遇到这种问题的解决方式一般是使用ViewPager(父View),和ChildViewPager(子View),一般的做法就是在子View中接管Touch事件,当子Viewr中可以进行左滑和右滑操作时,禁止父View的滑动,而当子View滑动到底的时候,把Touch事件交出来给父View,同时允许父View进行滑动。基本的解决思路就是这样的。首先在开始之前,对于RN下手势事件不了解不熟悉的可以看下RN官方中文网站的介绍,地址如下:http://reactnative.cn/docs/0.43/gesture-responder-system.html
4.解决问题
首先我们找到ViewPager中对于手势控制的代码,同时将我们的分析思路用代码进行实现
onMoveShouldSetPanResponder: (e, gestureState) => {
let needMove=false;
//手指从左往右滑动
if(gestureState.dx>0&&this.state.currentPage>0){
needMove=true;
}
//手指从右往左滑动
if(gestureState.dx<0&&this.state.currentPage<this.props.dataSource.getPageCount()-1){
needMove=true;
}
if (Math.abs(gestureState.dx) > Math.abs(gestureState.dy)&&needMove) {
if (this.props.locked !== true && !this.fling) {
this.props.hasTouch && this.props.hasTouch(true);
return true;
}
}
},
判断手指是从左往右滑动的时候,并且当处于非第0项的时候,或者手指是从右往左滑动的时候,并且当处于非最后一项时候,那么此时的手势操作应该交给子View,同时可以看到代码
this.props.hasTouch && this.props.hasTouch(true);
意思就是告诉父View,此时我接管了手势操作,并且本次滑动操作成功。那么同理,当不需要滑动操作的时候应该告诉父View,我不需要滑动操作了。果然在ViewPager的release方法中找到了该方法的调用
var release = (e, gestureState) => {
var relativeGestureDistance = gestureState.dx / deviceWidth,
//lastPageIndex = this.props.children.length - 1,
vx = gestureState.vx;
var step = 0;
if (relativeGestureDistance < -0.5 || (relativeGestureDistance < 0 && vx <= -1e-6)) {
step = 1;
} else if (relativeGestureDistance > 0.5 || (relativeGestureDistance > 0 && vx >= 1e-6)) {
step = -1;
}
this.props.hasTouch && this.props.hasTouch(false);
this.movePage(step, gestureState);
}
有了这些之后,我们就可以在父View之中根据这状态来进行相关的操作了
<ScrollableTabView
locked={this.state.isLocked}
>
{this._getChildItem()}
</ScrollableTabView>
//true表示内部需要滑动,此时外部需要lock住
_hasTouch = (isTouch) => {
this.setState({isLocked: isTouch})
}
通过对ScrollableTabView属性的修改来进行左右滑动的控制。我们来看下分别在ios和android下的效果
从效果上来看偶尔会有误触的情况,但是总体上的效果还可以接受
5.最后
作者接触RN还不到一个月的时间,之前一直是Android开发,能力有限,现在更多的是使用一些比较成熟的框架或者组件。当然要根据一些业务的需求进行修改。最后,奉上例子的Github地址:https://github.com/hzl123456/ChildViewPagerDemo
(记得修改ViewPager的代码)