Flutter如何实现支持左右滑动返回布尔值的滑动确认按钮
左右滑动状态返回按钮实现方案
你可以通过修改原有代码的回调逻辑、滑动限制实现双向滑动并返回布尔状态的需求:
核心修改点
- 替换原有无返回值的回调类型为可传递布尔值的
ValueChanged<bool> - 移除滑块滑到右侧后禁止滑动的限制,支持双向滑动切换
- 滑动结束时根据滑块位置自动归位到对应端点,同时向外传递当前状态(右滑激活返回
true,左滑复位返回false)
修改后的完整代码
import 'package:flutter/material.dart'; class SwipeOnOffButton extends StatefulWidget { final String? timer; final double? timerSize; final TextStyle? timerStyle; final double height; final double width; final Color? backgroundColor; final Color? disableBackgroundColor; final Color? replaceBackgroundColor; final Color? foregroundColor; final Color? iconColor; final IconData? leftIcon; final IconData? rightIcon; final double? iconSize; final String? text; final TextStyle? textStyle; // 替换原有VoidCallback为支持传递布尔值的回调 required final ValueChanged<bool> onStatusChanged; final BorderRadius? foregroundRadius; final BorderRadius? backgroundRadius; final bool disable; // 可选:添加初始状态参数 final bool initialValue; const SwipeOnOffButton({ Key? key, this.timer, this.timerSize, this.timerStyle, this.height = 48.0, this.width = 300, this.backgroundColor, this.disableBackgroundColor, this.foregroundColor, this.iconColor, this.leftIcon, this.text, this.textStyle, required this.onStatusChanged, this.foregroundRadius, this.backgroundRadius, this.rightIcon, this.iconSize, this.replaceBackgroundColor, this.disable = false, this.initialValue = false, }) : super(key: key); @override State<StatefulWidget> createState() { return SwipeOnOffButtonState(); } } class SwipeOnOffButtonState extends State<SwipeOnOffButton> { double _position = 0; int _duration = 0; late bool _isSwipe; @override void initState() { super.initState(); _isSwipe = widget.initialValue; // 初始状态如果为激活,滑块位置直接到最右侧 _position = _isSwipe ? widget.width - widget.height : 0; } double getPosition() { if (widget.disable) _position = 0; if (_position < 0) { return 0; } else if (_position > widget.width - widget.height) { return widget.width - widget.height; } else { return _position; } } Color getColor() { if (!widget.disable) { if (_position > 0) { return widget.replaceBackgroundColor ?? Colors.green; } else { return widget.backgroundColor ?? Colors.orange; } } else { return widget.disableBackgroundColor ?? Colors.black; } } void updatePosition(details) { if (!widget.disable) { if (details is DragEndDetails) { setState(() { _duration = 100; // 滑动结束判断位置:超过一半宽度则到最右,否则回到最左 if (_position > (widget.width - widget.height) / 2) { _position = widget.width - widget.height; _isSwipe = true; } else { _position = 0; _isSwipe = false; } // 向外传递当前状态 widget.onStatusChanged(_isSwipe); }); } else if (details is DragUpdateDetails) { setState(() { _duration = 0; // 移除原来的_isSwipe判断限制,支持双向滑动 _position = details.localPosition.dx - (widget.height / 2); }); } } else { _position = 0; } } void swipeReleased(details) { updatePosition(details); } @override Widget build(BuildContext context) { return Container( height: widget.height, width: widget.width, decoration: BoxDecoration( borderRadius: widget.backgroundRadius ?? BorderRadius.all(Radius.circular(widget.height)), color: !widget.disable ? widget.backgroundColor ?? Colors.orange : Colors.black, ), child: Stack( children: <Widget>[ AnimatedContainer( height: widget.height, width: getPosition() + widget.height, duration: Duration(milliseconds: _duration), curve: Curves.bounceOut, decoration: BoxDecoration( borderRadius: widget.backgroundRadius ?? BorderRadius.all(Radius.circular(widget.height)), color: getColor()), ), Center( child: Text( widget.text ?? "Start", style: widget.textStyle ?? Theme.of(context).textTheme.labelLarge?.copyWith(color: Colors.white) ?? TextStyle(color: Colors.white), ), ), AnimatedPositioned( duration: Duration(milliseconds: _duration), curve: Curves.bounceOut, left: getPosition(), child: GestureDetector( onPanUpdate: (details) => updatePosition(details), onPanEnd: (details) => swipeReleased(details), child: !_isSwipe ? Container( height: widget.height, width: widget.height, decoration: BoxDecoration( borderRadius: widget.foregroundRadius ?? BorderRadius.all( Radius.circular(widget.height / 2), ), color: widget.foregroundColor ?? Colors.white.withOpacity(0.24), ), child: Icon( widget.leftIcon ?? Icons.arrow_circle_right_rounded, color: widget.iconColor ?? Colors.white, size: widget.iconSize ?? 20.0, ), ) : Container( height: widget.height, width: widget.height, decoration: BoxDecoration( borderRadius: widget.foregroundRadius ?? BorderRadius.all( Radius.circular(widget.height / 2), ), color: widget.foregroundColor ?? Colors.white.withOpacity(0.24), ), child: Icon( widget.rightIcon ?? Icons.check_circle_rounded, color: widget.iconColor ?? Colors.white, size: widget.iconSize ?? 20.0, ), ), ), ), ], ), ); } }
使用示例
SwipeOnOffButton( width: 250, height: 50, text: "滑动解锁", backgroundColor: Colors.grey[300], replaceBackgroundColor: Colors.greenAccent, onStatusChanged: (bool status) { // 右滑完成返回true,左滑复位返回false debugPrint("当前滑动状态:$status"); // 这里可以写对应状态的业务逻辑 }, )
内容的提问来源于stack exchange,提问作者Afdal
相关产品推荐
相关产品推荐

