React Native中的FlatLis是一个加载多条数据的滚动控件,虽然狠好用,但是在Android手机中有一个问题:
如果数据只有几条,并且这几条数据不足以铺满整个屏幕,比如只有一条数据,这一条数据的高度是500px,那么这时FlatList是无法上下滑动的,我们在该条item上滑动时,无论滑动的距离是多少,只要手指还是在该item上抬起,那么就会触发点击事件。尤其是在item的高度比较大时,这个问题就明显了,因为用户本来是想要滑动一下的,并不想触发点击事件,所以问题必须解决。
大致思路是:
因为是FlatList带有这样的问题,可以考虑修改系统FlatList的功能,但是修改系统控件风险高,难度大,并且控件是在node_modules目录中,这个目录比较大,我们一般是不提交代码到git仓库中的,所以如果修改了系统控件,就必须要提交该部分的代码,比较费事。
既然这样不行,我们就换一种方式。问题出现在滑动item时出现,那么我们给item添加事件的处理,拦截滑动事件。因为是在item中滑动比较大的距离时仍然会触发点击事件,所以我们不需要拦截点击事件,只需要拦截滑动事件即可,如果滑动具体大于某一个值,我们直接把事件拦截掉,但是不做任何处理,结果是FlatList拿不到事件,也就无法触发点击事件。在系统中,点击事件是有一个滑动范围的,比如在某个系统手机中如果手指在屏幕中滑动的距离小于8,那么就认为是点击事件,而不是滑动事件。我们也做同样的处理,比如我们自己规定,如果滑动范围小于10,那么就认为是点击事件,我们不做任何拦截,仍由FlatList自己去处理,如果滑动范围大于了10,那么就认为这是滑动事件而不是点击事件,此时我们把事件拦截掉即可,这样就可以解决FlatList的内容在不满一屏时,如果在某个item上滑动,不管滑动距离是多少,只要手指还是在该item上抬起,就会触发点击事件的问题。
项目中肯定会有多个页面需要使用到FlatList,总不能给每个item都添加拦截处理,所以封装一个item,代码很简单,如下:
export default class GestureHandlerView extends Component {
componentWillMount() {
this._panResponder = PanResponder.create({
// 拦截move事件
onMoveShouldSetPanResponder: (evt, gestureState) => {
return Math.abs(gestureState.dy) > 10;
},
});
}
render() {
return (
<View style={this.props.style}
{...this._panResponder.panHandlers}>
{this.props.children}
</View>
);
}
}
使用起来也很简单,在FlatList的renderItem中把根View由之前的View换成我们自己的GestureHandlerView即可,并且使用这个封装的View就像使用系统的View完全一样,可以添加任何View可以添加的属性、样式。