Flutter中如何创建支持选择天、时、分的AlertDialog?
实现带滚动选择器的定时器弹窗
下面是适合新手的实现方案,用Flutter官方组件构建符合需求的滚动选择弹窗,无需依赖第三方包:
核心思路
用AlertDialog作为弹窗容器,内部嵌套三个CupertinoPicker分别处理天、时、分的滚动选择,同时通过状态管理控制选择范围的最大值限制(6天23小时59分),固定弹窗和选择器尺寸避免空间占用过大。
完整代码示例
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class TimerPickerDialog extends StatefulWidget { const TimerPickerDialog({super.key}); @override State<TimerPickerDialog> createState() => _TimerPickerDialogState(); } class _TimerPickerDialogState extends State<TimerPickerDialog> { // 初始选中值 int _selectedDays = 0; int _selectedHours = 0; int _selectedMinutes = 0; // 生成各选择器的可选范围 List<int> get _dayOptions => List.generate(7, (index) => index); // 0-6天 List<int> get _hourOptions => List.generate(24, (index) => index); // 0-23时 List<int> get _minuteOptions => List.generate(60, (index) => index); // 0-59分 @override Widget build(BuildContext context) { return AlertDialog( title: const Text('设置定时器'), content: SizedBox( height: 180, // 固定弹窗高度避免过度占用屏幕 child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ // 天选择器 _buildPicker( options: _dayOptions, selectedValue: _selectedDays, onSelectedItemChanged: (index) { setState(() { _selectedDays = _dayOptions[index]; // 当天数设为6时,若小时超过23则重置为23 if (_selectedDays == 6 && _selectedHours > 23) { _selectedHours = 23; } // 6天23小时时,若分钟超过59则重置为59 if (_selectedDays == 6 && _selectedHours == 23 && _selectedMinutes > 59) { _selectedMinutes = 59; } }); }, label: '天', ), // 小时选择器 _buildPicker( options: _hourOptions, selectedValue: _selectedHours, onSelectedItemChanged: (index) { setState(() { _selectedHours = _hourOptions[index]; // 6天23小时时,若分钟超过59则重置为59 if (_selectedDays == 6 && _selectedHours == 23 && _selectedMinutes > 59) { _selectedMinutes = 59; } }); }, label: '时', ), // 分钟选择器 _buildPicker( options: _minuteOptions, selectedValue: _selectedMinutes, onSelectedItemChanged: (index) { setState(() { _selectedMinutes = _minuteOptions[index]; }); }, label: '分', ), ], ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('取消'), ), TextButton( onPressed: () { // 返回选中结果,可替换为你的业务逻辑 Navigator.pop(context, { 'days': _selectedDays, 'hours': _selectedHours, 'minutes': _selectedMinutes, }); }, child: const Text('确认'), ), ], ); } // 封装通用选择器组件,减少重复代码 Widget _buildPicker({ required List<int> options, required int selectedValue, required ValueChanged<int> onSelectedItemChanged, required String label, }) { return Column( children: [ Text(label), const SizedBox(height: 8), SizedBox( width: 60, // 固定选择器宽度避免布局混乱 child: CupertinoPicker( magnification: 1.2, squeeze: 1.2, useMagnifier: true, itemExtent: 32, // 单个选项的高度 scrollController: FixedExtentScrollController( initialItem: options.indexOf(selectedValue), ), onSelectedItemChanged: onSelectedItemChanged, children: options.map((value) { return Center( child: Text( '$value', style: const TextStyle(fontSize: 16), ), ); }).toList(), ), ), ], ); } } // 弹窗调用示例,可直接在按钮点击事件中使用 void showTimerPicker(BuildContext context) { showDialog( context: context, builder: (context) => const TimerPickerDialog(), ).then((result) { if (result != null) { // 处理选中结果,比如更新页面状态或打印 print('选中:${result['days']}天 ${result['hours']}时 ${result['minutes']}分'); } }); }
关键说明
- 用
CupertinoPicker实现你需要的滚动选择样式,适配Material风格弹窗 - 固定弹窗和选择器的尺寸,彻底解决DropdownBox弹窗过大的问题
- 通过状态联动实现最大值限制:当选中6天时,自动修正小时和分钟不超过23和59
- 封装的
_buildPicker方法简化了代码结构,新手易读易改 - 调用示例中的
showTimerPicker函数可直接嵌入按钮点击事件,快速启用功能
内容的提问来源于stack exchange,提问作者AKC
相关产品推荐
相关产品推荐

