Flutter 仿ios自定义一个DatePicker
2021-02-08 本文已影响0人
赵哥窟
Screenshot_1612747215.png
编辑个人资料,修改生日的时候需要用到,需求就是如果传了日期就要滚动到传的日期位置,如果没有穿就是系统当前时间。所以动手撸一个,有需要的同学可以拿去做轮子。
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/screenutil.dart';
import 'package:toofoo/common/color/colorsUtil.dart';
typedef OnSelectedDate = void Function(String date);
class DatePicker extends StatefulWidget {
DatePicker(
{this.onSelectedDate,
this.selectedDate,
this.startYear = 1970,
this.endYear = 2500});
// 结果返回
final OnSelectedDate onSelectedDate;
final String selectedDate; //选中的时间
final int startYear;
final int endYear;
@override
_DatePickerState createState() => _DatePickerState();
}
class _DatePickerState extends State<DatePicker> {
//年数组
List<String> yearList = [];
//月数组
List<String> monthList = [];
//天数组
List<String> dayList = [];
//年的索引
int yearIndex;
//月的索引
int monthIndex;
//天的索引
int dayIndex;
//每列的宽度
double _columnWidth;
FixedExtentScrollController yearScrollController;
FixedExtentScrollController monthScrollController;
FixedExtentScrollController dayScrollController;
@override
void initState() {
super.initState();
_columnWidth = ScreenUtil.screenWidth / 3;
_setupData();
_initSelectedIndex();
}
@override
void dispose() {
yearScrollController.dispose();
monthScrollController.dispose();
dayScrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_headerWidget(),
_datePicker(),
],
),
);
}
///初始化数据
void _setupData() {
for (int i = widget.startYear; i <= widget.endYear; i++) {
yearList.add(i.toString());
}
for (int i = 1; i <= 12; i++) {
monthList.add(i.toString().padLeft(2, '0'));
}
// 初始化天数(当前时间系统时间的天数)
int year = DateTime.now().year;
int month;
if (widget.selectedDate == null || widget.selectedDate.isEmpty) {
month = DateTime.now().month;
} else {
List<String> date = widget.selectedDate.split('-');
month = int.parse(date[1]);
}
dayList = _getDayList(year: year, month: month);
}
int _getDayCount({int year, int month}) {
int dayCount = DateTime(year, month + 1, 0).day;
return dayCount;
}
List<String> _getDayList({int year, int month}) {
List<String> dayList = [];
int days = _getDayCount(year: year, month: month);
for (int i = 1; i <= days; i++) {
dayList.add(i.toString().padLeft(2, '0'));
}
return dayList;
}
///选中年月后更新天
void _updateDayList() {
int year = int.parse(yearList[yearIndex]);
int month = int.parse(monthList[monthIndex]);
setState(() {
dayIndex = 0;
dayList = _getDayList(year: year, month: month);
if (dayScrollController.positions.length > 0) {
dayScrollController.jumpTo(0);
}
});
}
///初始化时间索引
void _initSelectedIndex() {
final List uniqueYearList = Set.from(yearList).toList();
final List uniqueMonthList = Set.from(monthList).toList();
final List uniqueDayList = Set.from(dayList).toList();
///获取索引
if (widget.selectedDate != null && widget.selectedDate.isNotEmpty) {
///传了选中日期的时候
List<String> date = widget.selectedDate.split('-');
setState(() {
yearIndex = uniqueYearList.indexOf(date[0]);
monthIndex = uniqueMonthList.indexOf(date[1]);
dayIndex = uniqueDayList.indexOf(date[2]);
});
} else {
///没有传选中日期默认当前系统时间
String year = DateTime.now().year.toString();
String month = DateTime.now().month.toString().padLeft(2, '0');
String day = DateTime.now().day.toString().padLeft(2, '0');
setState(() {
yearIndex = uniqueYearList.indexOf(year);
monthIndex = uniqueMonthList.indexOf(month);
dayIndex = uniqueDayList.indexOf(day);
});
}
yearScrollController = FixedExtentScrollController(initialItem: yearIndex);
monthScrollController =
FixedExtentScrollController(initialItem: monthIndex);
dayScrollController = FixedExtentScrollController(initialItem: dayIndex);
}
Widget _headerWidget() {
return Container(
height: 60,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FlatButton(
child: Text(
'取消',
style: TextStyle(
fontSize: 16.0,
),
),
onPressed: () {
Navigator.pop(context);
},
),
FlatButton(
child: Text(
'确定',
style: TextStyle(
fontSize: 16.0,
),
),
onPressed: () {
if (widget.onSelectedDate != null) {
String date = yearList[yearIndex]+'-'+monthList[monthIndex]+'-'+dayList[dayIndex];
widget.onSelectedDate(date);
}
},
),
]),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey.withOpacity(0.1), width: 1)),
),
);
}
Widget _datePicker() {
return Container(
color: Colors.white,
height: 200,
child: Stack(
children: [
Row(
children: <Widget>[
Expanded(child: _yearPickerView()),
Expanded(child: _monthPickerView()),
Expanded(child: _dayPickerView()),
],
),
Container(
color: ColorsUtil.hexStringColor('D1D1D6'),
margin: EdgeInsets.only(top: 78),
height: 1,
),
Container(
color: ColorsUtil.hexStringColor('D1D1D6'),
margin: EdgeInsets.only(top: 124),
height: 1,
),
Container(
margin: EdgeInsets.only(top: 78),
child: Row(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.only(left: _columnWidth - 40, top: 9),
child: Text(
'年',
style: TextStyle(color: Colors.grey, fontSize: 16),
maxLines: 1,
),
),
),
Expanded(
child: Padding(
padding: EdgeInsets.only(left: _columnWidth - 50, top: 9),
child: Text(
'月',
style: TextStyle(color: Colors.grey, fontSize: 16),
maxLines: 1,
),
),
),
Expanded(
child: Padding(
padding: EdgeInsets.only(left: _columnWidth - 50, top: 9),
child: Text(
'日',
style: TextStyle(color: Colors.grey, fontSize: 16),
maxLines: 1,
),
),
),
],
),
),
],
),
);
}
///年
Widget _yearPickerView() {
return Container(
child: CupertinoPicker(
scrollController: yearScrollController,
children: _buildYearWidget(),
looping: true,
selectionOverlay: Center(),
onSelectedItemChanged: (index) {
setState(() {
yearIndex = index;
});
_updateDayList();
},
itemExtent: 44,
),
);
}
///月
Widget _monthPickerView() {
return Container(
child: CupertinoPicker(
scrollController: monthScrollController,
children: _buildMonthWidget(),
looping: true,
selectionOverlay: Center(),
onSelectedItemChanged: (index) {
setState(() {
monthIndex = index;
});
_updateDayList();
},
itemExtent: 44,
),
);
}
///日
Widget _dayPickerView() {
return Container(
child: CupertinoPicker(
scrollController: dayScrollController,
children: _buildDayWidget(),
looping: true,
selectionOverlay: Center(),
onSelectedItemChanged: (index) {
setState(() {
dayIndex = index;
});
},
itemExtent: 44,
),
);
}
///年Widget
List<Widget> _buildYearWidget() {
List<Widget> yearListWidget = []; //先建一个数组用于存放循环生成的widget
Widget content; //单独一个widget组件,用于返回需要生成的内容widget
for (var item in yearList) {
yearListWidget.add(
new Center(
child: Text(
item,
style: TextStyle(color: Colors.black87, fontSize: 16),
maxLines: 1,
),
),
);
}
return yearListWidget;
}
///月Widget
List<Widget> _buildMonthWidget() {
List<Widget> monthListWidget = []; //先建一个数组用于存放循环生成的widget
Widget content; //单独一个widget组件,用于返回需要生成的内容widget
for (var item in monthList) {
monthListWidget.add(
new Center(
child: Text(
item,
style: TextStyle(color: Colors.black87, fontSize: 16),
maxLines: 1,
),
),
);
}
return monthListWidget;
}
///日Widget
List<Widget> _buildDayWidget() {
List<Widget> dayListWidget = []; //先建一个数组用于存放循环生成的widget
Widget content; //单独一个widget组件,用于返回需要生成的内容widget
for (var item in dayList) {
dayListWidget.add(
new Center(
child: Text(
item,
style: TextStyle(color: Colors.black87, fontSize: 16),
maxLines: 1,
),
),
);
}
return dayListWidget;
}
}
使用
void _showBirthdayDialog(BuildContext context, Dispatch dispatch) {
showModalBottomSheet<void>(
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
builder: (BuildContext context) {
return DatePicker(
endYear: DateTime.now().year,
selectedDate: null,
onSelectedDate: (String date) {
Navigator.pop(context);
},
);
});
}