flutter_integrated_whb/lib/customWidget/picker/CupertinoDatePicker.dart

221 lines
6.7 KiB
Dart

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<DateTime?> showDate(BuildContext context) {
return showModalBottomSheet<DateTime>(
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<int> years = List.generate(101, (i) => 1970 + i);
final List<int> months = List.generate(12, (i) => i + 1);
final List<int> days = List.generate(31, (i) => i + 1);
final List<int> hours = List.generate(24, (i) => i);
final List<int> 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<String> items,
required ValueChanged<int> onSelected,
}) {
return Expanded(
child: CupertinoPicker.builder(
scrollController: controller,
itemExtent: 32,
childCount: items.length,
onSelectedItemChanged: onSelected,
itemBuilder: (context, index) {
return Center(child: Text(items[index]));
},
),
);
}
}