Flutter实现含图标计时器的左侧按钮与右侧提交按钮的行布局及弹窗
实现Flutter Row布局与底部弹窗方案
整体布局框架
先搭好核心的Row结构,让左右两个按钮分别靠向屏幕两端,再给整体加些内边距避免贴边:
Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), children: [ // 左侧带计时器的播放/暂停按钮 const TimerControlButton(), // 右侧提交按钮 _buildSubmitButton(), ], )
左侧播放/暂停+计时器按钮
这个按钮需要维护播放状态和剩余时间,所以用StatefulWidget来实现:
class TimerControlButton extends StatefulWidget { const TimerControlButton({super.key}); @override State<TimerControlButton> createState() => _TimerControlButtonState(); } class _TimerControlButtonState extends State<TimerControlButton> { int _remainingSeconds = 20 * 60; // 初始20分钟 bool _isPlaying = false; Timer? _countdownTimer; // 把秒数格式化为 mm:ss 样式 String _formatTime(int seconds) { final minutes = (seconds ~/ 60).toString().padLeft(2, '0'); final secs = (seconds % 60).toString().padLeft(2, '0'); return '$minutes:$secs'; } // 切换播放/暂停逻辑 void _toggleTimer() { setState(() => _isPlaying = !_isPlaying); if (_isPlaying) { _countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) { setState(() { if (_remainingSeconds > 0) { _remainingSeconds--; } else { _countdownTimer?.cancel(); _isPlaying = false; } }); }); } else { _countdownTimer?.cancel(); } // 触发底部弹窗 _showBottomSheet(); } // 显示底部弹窗 void _showBottomSheet() { showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), builder: (context) { return Container( padding: const EdgeInsets.all(16), height: 220, child: const Center( child: Text('这里可以放弹窗的自定义内容哦'), ), ); }, ); } @override void dispose() { _countdownTimer?.cancel(); // 页面销毁时取消计时器,防止内存泄漏 super.dispose(); } @override Widget build(BuildContext context) { return TextButton( onPressed: _toggleTimer, child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(_isPlaying ? Icons.pause_rounded : Icons.play_arrow_rounded), const SizedBox(width: 8), Text(_formatTime(_remainingSeconds)), ], ), ); } }
右侧提交按钮
逻辑很直接,点击后直接唤起底部弹窗即可:
Widget _buildSubmitButton() { return ElevatedButton( onPressed: () { showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), builder: (context) { return Container( padding: const EdgeInsets.all(16), height: 220, child: const Center( child: Text('提交操作的弹窗内容'), ), ); }, ); }, child: const Text('提交'), ); }
小提示
- 弹窗的样式和内容可以完全自定义,比如加表单、操作按钮或者滚动视图
- 如果需要重置计时器,可以给按钮加个长按逻辑或者额外的重置按钮,直接把
_remainingSeconds设回20*60即可
内容的提问来源于stack exchange,提问作者Gaurav Kumar
相关产品推荐
相关产品推荐

