React Native Swipeable 长滑自动触发删除功能实现问题
react-native-gesture-handler Swipeable 滑动超阈值自动触发删除实现方案
核心实现逻辑
利用Swipeable自带的进度动画值、阈值回调,配合Animated动画实现目标按钮拉伸占满、自动触发操作的效果,不需要引入额外依赖。
具体实现步骤
- 调整Swipeable组件配置属性
补充阈值、越界控制、打开回调三个核心属性,替换原来的固定数值阈值为比例阈值,关闭右侧越界回弹避免动画异常:<Swipeable ref={updateRef} friction={2} leftThreshold={80} rightThreshold={0.6} // 滑动露出右侧操作区60%宽度时判定为触发状态 overshootRight={false} onSwipeableRightOpen={handleAutoTriggerAction} renderRightActions={renderRightActions} > {/* 列表项内容 */} children </Swipeable> - 改造右侧操作按钮动画
利用组件传入的progress动画值(取值0~1,0为完全未滑动,1为滑到触发阈值位置),给目标操作按钮加宽度拉伸动画,非目标按钮加收缩隐藏动画:
调整const renderRightAction = ( text: string, color: string, itemWidth: number, progress: Animated.AnimatedInterpolation<number>, imageUrl: string, isTargetAction = false // 标记是否是滑动超阈值要自动触发的按钮 ) => { const pressHandler = () => { close(); // 按钮点击业务逻辑 console.log(text); }; // 按钮位移动画 const translateX = progress.interpolate({ inputRange: [0, 1], outputRange: [itemWidth, 0], }); // 按钮宽度动画:目标按钮滑到阈值时占满总宽度,其余按钮收缩为0 const widthAnim = isTargetAction ? progress.interpolate({ inputRange: [0, 0.8, 1], outputRange: [itemWidth, itemWidth, itemWidth * 2] // 两个按钮总宽度为84*2=168,此处匹配总宽度 }) : progress.interpolate({ inputRange: [0, 0.8, 1], outputRange: [itemWidth, itemWidth, 0] }); return ( <Animated.View style={{ width: widthAnim, transform: [{ translateX }] }}> <RectButton style={[styles.rightAction, { backgroundColor: color }]} onPress={pressHandler} > <SvgXml xml={imageUrl} width={wp(16)} height={wp(16)} /> <Text style={styles.actionText}>{text}</Text> </RectButton> </Animated.View> ); };renderRightActions方法,给需要自动触发的删除/隐藏按钮打标记,同时给操作区容器设置固定总宽度:const renderRightActions = (progress: Animated.AnimatedInterpolation<number>) => ( <View style={[styles.renderRightActionsContainer, { width: 168 }]}> {renderRightAction('Favoritt', Colors.lightBeige, 84, progress, Images.Favourite)} {/* 第二个按钮作为自动触发的目标按钮,传入isTargetAction=true */} {renderRightAction('Skjul', Colors.primaryBackground, 84, progress, Images.CloseEye, true)} </View> ); - 实现自动触发回调
滑动达到阈值后会自动触发该回调,执行关闭动画+对应业务逻辑:const handleAutoTriggerAction = () => { close(); // 此处写删除/隐藏列表项的实际业务逻辑,比如更新列表数据源、调用接口等 console.log('已自动触发隐藏/删除操作'); };
可选扩展:滑动不松手即刻触发
如果不需要等用户松手,只要滑动距离超过阈值就立刻触发操作,可以在renderRightActions里监听dragX动画值,数值达到判定条件时直接调用触发方法即可,注意加锁避免重复触发:
const hasTriggered = useRef(false); const renderRightActions = (progress: Animated.AnimatedInterpolation<number>, dragX: Animated.AnimatedInterpolation<number>) => { dragX.addListener(({ value }) => { // 左滑时dragX为负值,绝对值超过120时触发 if (!hasTriggered.current && value < -120) { hasTriggered.current = true; handleAutoTriggerAction(); // 重置标记,下次滑动可重新触发 setTimeout(() => { hasTriggered.current = false; }, 500); } }); return ( <View style={[styles.renderRightActionsContainer, { width: 168 }]}> {renderRightAction('Favoritt', Colors.lightBeige, 84, progress, Images.Favourite)} {renderRightAction('Skjul', Colors.primaryBackground, 84, progress, Images.CloseEye, true)} </View> ); };
注意:如果使用监听dragX的方案,记得在组件卸载时移除listener避免内存泄漏。
内容的提问来源于stack exchange,提问作者mohsinali1317
相关产品推荐
相关产品推荐

