import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; /// 调用示例: /// DateTime? picked = await BottomDateTimePicker.show(context); /// if (picked != null) { /// print('用户选择的时间:$picked'); /// } class BottomDateTimePicker { static Future showDate(BuildContext context) { return showModalBottomSheet( context: context, backgroundColor: Colors.white, isScrollControlled: true, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(12)), ), builder: (_) => _InlineDateTimePickerContent(), ); } } class _InlineDateTimePickerContent extends StatefulWidget { @override State<_InlineDateTimePickerContent> createState() => _InlineDateTimePickerContentState(); } class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerContent> { // 数据源 final List years = List.generate(101, (i) => 1970 + i); final List months = List.generate(12, (i) => i + 1); final List days = List.generate(31, (i) => i + 1); final List hours = List.generate(24, (i) => i); final List minutes = List.generate(60, (i) => i); // Controllers late FixedExtentScrollController yearCtrl; late FixedExtentScrollController monthCtrl; late FixedExtentScrollController dayCtrl; late FixedExtentScrollController hourCtrl; late FixedExtentScrollController minuteCtrl; // 当前选中值 late int selectedYear; late int selectedMonth; late int selectedDay; late int selectedHour; late int selectedMinute; @override void initState() { super.initState(); final now = DateTime.now(); selectedYear = now.year; selectedMonth = now.month; selectedDay = now.day; selectedHour = now.hour; selectedMinute = now.minute; yearCtrl = FixedExtentScrollController(initialItem: years.indexOf(selectedYear)); monthCtrl = FixedExtentScrollController(initialItem: selectedMonth - 1); dayCtrl = FixedExtentScrollController(initialItem: selectedDay - 1); hourCtrl = FixedExtentScrollController(initialItem: selectedHour); minuteCtrl = FixedExtentScrollController(initialItem: selectedMinute); } @override void dispose() { yearCtrl.dispose(); monthCtrl.dispose(); dayCtrl.dispose(); hourCtrl.dispose(); minuteCtrl.dispose(); super.dispose(); } void _checkAndClampToNow() { final picked = DateTime(selectedYear, selectedMonth, selectedDay, selectedHour, selectedMinute); final now = DateTime.now(); if (picked.isAfter(now)) { // 回滚到当前时间 selectedYear = now.year; selectedMonth = now.month; selectedDay = now.day; selectedHour = now.hour; selectedMinute = now.minute; // 更新各滚轮位置 yearCtrl.jumpToItem(years.indexOf(selectedYear)); monthCtrl.jumpToItem(selectedMonth - 1); dayCtrl.jumpToItem(selectedDay - 1); hourCtrl.jumpToItem(selectedHour); minuteCtrl.jumpToItem(selectedMinute); } } @override Widget build(BuildContext context) { return SizedBox( height: 300, child: Column( children: [ // 顶部按钮 Padding( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text("取消", style: TextStyle(color: Colors.grey)), ), TextButton( onPressed: () { final result = DateTime( selectedYear, selectedMonth, selectedDay, selectedHour, selectedMinute, ); Navigator.of(context).pop(result); }, child: const Text("确定", style: TextStyle(color: Colors.blue)), ), ], ), ), const Divider(height: 1), // 五列数字滚轮 Expanded( child: Row( children: [ // 年 _buildPicker( controller: yearCtrl, items: years.map((e) => e.toString()).toList(), onSelected: (idx) { setState(() { selectedYear = years[idx]; _checkAndClampToNow(); }); }, ), // 月 _buildPicker( controller: monthCtrl, items: months.map((e) => e.toString().padLeft(2, '0')).toList(), onSelected: (idx) { setState(() { selectedMonth = months[idx]; _checkAndClampToNow(); }); }, ), // 日 _buildPicker( controller: dayCtrl, items: days.map((e) => e.toString().padLeft(2, '0')).toList(), onSelected: (idx) { setState(() { selectedDay = days[idx]; _checkAndClampToNow(); }); }, ), // 时 _buildPicker( controller: hourCtrl, items: hours.map((e) => e.toString().padLeft(2, '0')).toList(), onSelected: (idx) { setState(() { selectedHour = hours[idx]; _checkAndClampToNow(); }); }, ), // 分 _buildPicker( controller: minuteCtrl, items: minutes.map((e) => e.toString().padLeft(2, '0')).toList(), onSelected: (idx) { setState(() { selectedMinute = minutes[idx]; _checkAndClampToNow(); }); }, ), ], ), ), ], ), ); } Widget _buildPicker({ required FixedExtentScrollController controller, required List items, required ValueChanged onSelected, }) { return Expanded( child: CupertinoPicker.builder( scrollController: controller, itemExtent: 32, childCount: items.length, onSelectedItemChanged: onSelected, itemBuilder: (context, index) { return Center(child: Text(items[index])); }, ), ); } }