I recently needed to use ios-style hour and minute time pickers in my Flutter project.

So, CupertinoDatePicker, right out of the box, would be able to do that, but most of the projects in cupertino have a black background. So, CupertinoDatePicker can’t set the color of the text.

I happened to read an article about ListWheelViewport recently

It’s easy to masturbate yourself by the way that god leads.

The following code is the simplest example, which you can use to customize your own:

class CustomDatePicker extends StatefulWidget { CustomDatePicker({this.timeCallback, Key key}) : super(key: key); final ValueChanged<String> timeCallback; @override _CustomDatePickerState createState() => _CustomDatePickerState(); } class _CustomDatePickerState extends State<CustomDatePicker> { final _hours = List.generate(24, (i) => i.timeFormat); final _minutes = List.generate(60, (i) => i.timeFormat); var _hourViewIndex = 0; var _minuteViewIndex = 0; FixedExtentScrollController _hourController; FixedExtentScrollController _minuteController; @override void initState() { super.initState(); _nowTimeSetting(); } @override Widget build(BuildContext context) { return Container( child: Stack( children: [ Row( children: [ _hourView(), _minuteView(), ], ), Positioned( left: 16, right: 16, top: 68, child: Divider(), ), Positioned( left: 16, right: 16, top: 118, child: Divider(), ), ], ), ); } Widget _hourView() { return _timeWheel(times: _hours, isHour: true, controller: _hourController); } Widget _minuteView() { return _timeWheel( times: _minutes, isHour: false, controller: _minuteController); } Widget _timeWheel( {List<String> times, bool isHour, FixedExtentScrollController controller}) { return Flexible( child: Container( height: 190, child: ListWheelScrollView.useDelegate( controller: controller, childDelegate: ListWheelChildLoopingListDelegate( children: Times.map ((number) => _buildItem(number),).tolist (),), perspective: 0.006, itemExtent: 49, True, // magnIFICATION: 1.2, onSelectedItemChanged: (index) {if (isHour) {_hourViewIndex = index; } else { _minuteViewIndex = index; } final time = _hours[_hourViewIndex] + ":" + _minutes[_minuteViewIndex]; widget.timeCallback(time); },),),); } Widget _buildItem(String time) { return Container( key: ValueKey(time), alignment: Alignment.center, height: 50, color: Color(0xFF), child: Text( time, textDirection: TextDirection.rtl, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 23, color: Colors.white, ), ), ); } void _nowTimeSetting() { final nowTime = DateTime.now(); final nowHour = nowTime.hour.timeFormat; final nowMinute = nowTime.minute.timeFormat; _hourViewIndex = _hours.indexOf(nowHour); _minuteViewIndex = _minutes.indexOf(nowMinute); _hourController = FixedExtentScrollController(initialItem: _hourViewIndex); _minuteController = FixedExtentScrollController(initialItem: _minuteViewIndex); } @override void dispose() { _hourController.dispose(); _minuteController.dispose(); super.dispose(); } } extension on int { String get timeFormat { var string = this.toString(); return string.length == 2 ? string : "0" + string; }}Copy the code

1. The idea of the code is to first put two ListWheelViewPorts into a Row, the left is 0-24 hours, the right is 0-59 minutes, so we use two sets of data sources, how to split the two ListWheelViewports in the Row, I made a little attempt, can fix the width. Half of the screen, or use Flexible to wrap, if you have a better solution, please teach me.

2. Then I want to use the page to scroll to the current time, here I thought of using the ScrollController in ListWheelScrollView, but how to accurately calculate the time to scroll to the current time, I will not know for a while, while I am looking at the source code, while looking at the Api, Saw a subclass of ScrollController FixedExtentScrollController inside, by configuring the controller can at the time of initialization, scroll to the current time is accurate.

3. Finally, the current time, add a line above and below it to decorate, this one with the Stack in the most outer layer.