mh-rn-component
Version:
125 lines (123 loc) • 3.91 kB
Flow
import React, { useState, useRef } from 'react'
import { Animated, View, Text, StyleSheet, TouchableWithoutFeedback, ScrollView, PanResponder, PanResponderGestureState, GestureResponderEvent } from "react-native"
type Props = {
children?: any,
right?: () => JSX.Element
left?: () => JSX.Element
}
const SwipeCell = ({ children, ...rest }: Props) => {
// 用来判断是否有移动,用来做动画节流
const [moveHave, setMoveHave] = useState(false)
const [mainWidth, setMainWidth] = useState(0)
const [mainHeight, setMainHeight] = useState(0)
const rightWidth = useRef(0)
const leftwidth = useRef(0)
// 获取元素宽高
const layoutRight = (e: any) => {
rightWidth.current = e.nativeEvent.layout.width;
}
const layoutLeft = (e: any) => {
leftwidth.current = e.nativeEvent.layout.width;
}
// 回到固定位置动画
const springMove = (x: number) => {
return Animated.spring(cell, {
toValue: { x: x, y: 0 },
speed: 24,
overshootClamping: true,
useNativeDriver: false,
})
}
const cell = useRef<any>(new Animated.ValueXY()).current;
const touchHandel = useRef(
PanResponder.create({
onMoveShouldSetPanResponder: () => true,
onPanResponderGrant: () => {
cell.setOffset({
x: cell.x._value,
y: 0
});
},
onPanResponderMove: (e: GestureResponderEvent, gs: PanResponderGestureState) => {
if (gs.dx < 0) {
Animated.event(
[
null,
{ dx: cell.x, dy: cell.y },
], { useNativeDriver: false })(e, gs);
}
if (rest.left && gs.dx > 0) {
Animated.event(
[
null,
{ dx: cell.x, dy: cell.y },
], { useNativeDriver: false })(e, gs);
}
},
onPanResponderRelease: (e: GestureResponderEvent, gs: PanResponderGestureState) => {
cell.flattenOffset();
// 回弹
if (gs.dx > 10) {
springMove(leftwidth.current).start()
setMoveHave(true)
} else if (gs.dx < -10) {
springMove(-rightWidth.current).start()
setMoveHave(true)
} else if (gs.dx > -10 && gs.dx < 0) {
springMove(0).start()
}
// console.log(gs.dx, cell.x._value)
}
})
).current;
const reduction = () => {
if (moveHave) {
springMove(0).start()
setMoveHave(false)
}
}
return (
<View style={styles.swipe_cell} onLayout={(e: any) => { setMainWidth(e.nativeEvent.layout.width); setMainHeight(e.nativeEvent.layout.height) }}>
<Animated.View style={[{ transform: [{ translateX: cell.x }] }]} {...touchHandel.panHandlers}>
<TouchableWithoutFeedback onPress={reduction}>
<View style={[styles.main]}>
<View style={{ height: mainHeight, position: "absolute", left: -leftwidth.current }} onLayout={layoutLeft}>
{rest.left && rest.left()}
</View>
<View style={{ width: mainWidth }}>{children}</View>
<View style={{ height: mainHeight }} onLayout={layoutRight}>
{!rest.right && (<View style={styles.right}>
<Text style={{ color: "#fff" }}>删除</Text>
</View>)}
{rest.right && rest.right()}
</View>
</View>
</TouchableWithoutFeedback>
</Animated.View >
</View>
)
}
const styles = StyleSheet.create({
swipe_cell: {
flex: 1,
minHeight: 20,
flexDirection: "row",
overflow: "hidden"
},
main: {
alignItems: "center",
justifyContent: "flex-start",
flexDirection: "row",
position: "relative",
},
right: {
height: "100%",
backgroundColor: "#de1c31",
color: "#fff",
alignItems: "center",
justifyContent: "center",
paddingLeft: 10,
paddingRight: 10,
},
})
export default SwipeCell