最近公司全面推行使用React-Native进行跨平台开发,虽然我对这方面不熟悉,而且对RN也没有啥兴趣,但是也没办法,也没有学啥js和RN的东西,直接刚。正好要实现一个侧滑删除功能,网上搜了一波,没发现啥好的说明,于是决定自己实现一波。但由于自己没有系统的学过RN,所以写的不怎么给力。
首先看下效果图,如下所示:
要写这个组件,有两个问题要先解决,
- 这个页面已经存在了,我如何能在做较小修改的情况下,实现这样一个侧滑删除的组件?
- 如果不修改原来的组件添加滑动手势?
经过考虑之后,决定自定义一个容器组件,只要包裹上一层并提供对应的信息,即可拥有侧滑删除的功能,也许这并不是最好的实现方式,但起码功能已经有了。在我项目里的使用方式如下所示:
return (
<MessageSwiper actions={
[
<MessageSwiperAction title={
'删除'} color={
'red'} action={
this.actionDemo.bind(this)} confirm={
this.confirmDemo.bind(this)} animatable={
true}/>,
<MessageSwiperAction title={
'移动'} color={
'green'} action={
this.actionDemo.bind(this)} confirm={
this.confirmDemo.bind(this)} animatable={
true}/>
]}>
<View style={
style.container}>
<View style={
{
flexDirection: 'row'}}>
<Image style={
style.msgImage} source={
this.props.item.type === 'businessCustomerService' ? {
uri: this.props.item.serviceLogo} : messageImage[this.props.item.type]}/>
{
comp}
</View>
<View style={
{
flexDirection: 'column', flex: 1}}>
<View style={
{
flexDirection: 'row'}}>
<Text style={
style.msgTitle}>{
this.props.item.serviceName}</Text>
<Text style={
style.msgTime}>{
this._getDate(this.props.item.nowMsgTime)}</Text>
</View>
<Text style={
style.msgSubTitle} ellipsizeMode={
'tail'}
numberOfLines={
1}>{
this.props.item.nowMsgContent}</Text>
<View style={
style.separator}/>
</View>
</View>
</MessageSwiper>
);
可以看到,只要在原来的组件外层使用一个并提供actions即可,在我看来,这样操作对原来的组件影响是最小的。想法有了,但是接下来就是需要怎么实现了。
首先从MessageSwiperAction开始,其实这个类只是一个空类,里面并没有使用实际代码,使用这个类的方式是用于在外侧编写一些需要的属性或者将来有什么其他的扩展需要做预留。
然后从render方法开始,做为一个容器组件,我们可以使用this.props.children拿到里面的子组件,render方法的代码如下所示:
render() {
return (
<Animated.View style={
{
transform: [
{
translateX: this.state.translateAnim}
]
}}>
<View style={
style.swipeContainer}>
{
this.getActions()}
</View>
<View
{
...this._panResponder.panHandlers}
ref={
'maskView'}
>
{
this.props.children}
</View>
</Animated.View>
);
}
使用Animated.View来做删除动画,其实一个侧滑删除是由两个叠在一起的View组成的,所以可以看到,外层传入了actions之后,我使用了一个View包装,其中样式表如下所示:
const style = StyleSheet.create({
swipeContainer: {
flex: 1,
flexDirection: 'row',
backgroundColor: 'white',
alignItems: 'flex-start',
justifyContent: 'flex-end',
position: 'absolute',
top: 0.0,
bottom: 0.0,
left: 0.0,
right: 0.0,
},
actionTitle: {
color: 'white',
textAlign: 'center',
},
actionContainer: {
width: 80.0,
height: '100%',
alignItems: 'center',
justifyContent: 'center'
}
})
要想让一个View叠在另外一个View的下面,我们需要将position修改为absolute,然后从右至左依次排列。之前已经提出了两个问题,现在先来解决第一个问题:
以上说过,我们可以使用this.props.children来获取到当前容器组件的子组件,所以我们只需要使用{this.props.children}即可。
第二个问题:
因为使用的是{this.props.children},所以我没办法直接在这里添加手势,最后我决定在外层包裹一层View,用以添加手势。这样既可以实现侧滑又可以不影响原有组件。
添加手势的方法如下所示:
UNSAFE_componentWillMount(): void {
this._panResponder = PanResponder.create({
// 要求成为响应者:
onStartShouldSetPanResponder: (evt, gestureState) => true,
onStartShouldSetPanResponderCapture: (evt, gestureState