Flutter:CupertinoDatePicker不好使,自己撸一个小时与分钟的时间选择器
最近在自己的Flutter项目中需要使用iOS风格的小时与分钟的时间选择器。
本来开箱即用的CupertinoDatePicker就基本上可以满足需求,奈何项目里大部分都是黑色背景,而CupertinoDatePicker无法设置文本颜色,结果就是一团黑,根本看不清楚选择的什么时间。
借着大神引领的路,自己撸一个就很简单了。
下面代码只是最最简单的例子,大家可以借鉴其中,自己进行自定义:
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,
/// 是否放大
useMagnifier: 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;
}
}
1.代码的思路是先把两个ListWheelViewport放到一个Row中,左边的是0-24小时,右边的0-59分钟,于是用了两套数据源,在Row中如何让两个ListWheelViewport平分,我稍微做了一个尝试,可以固定宽度,屏幕的一半,或者使用Flexible进行包裹,如果大家有更好的解决方案,可以教教我。
2.然后就是希望点进页面的使用能够滚动到当前时间,这里我想到了在ListWheelScrollView中使用ScrollController,不过如何精确计算滚动到当前的时间,一时半会还没不知道,就在我边查看源码,边看Api的时候,在里面看到了ScrollController的子类FixedExtentScrollController,通过配置该控制器可以在初始化的时候,就准确的滚动到当前时间。
3.最后,就是当前的的时间,在其上下加上横线进行修饰,这个用Stack在最外层包裹即可。
转载自:https://juejin.cn/post/6913791574581182478