Flutter 仿ios自定义一个DatePicker

2021-03-02 14:32:36 浏览数 (1)

Screenshot_1612747215.png

编辑个人资料,修改生日的时候需要用到,需求就是如果传了日期就要滚动到传的日期位置,如果没有穿就是系统当前时间。所以动手撸一个,有需要的同学可以拿去做轮子。

代码语言:javascript复制
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;
  }
}

使用

代码语言:javascript复制
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);
          },
        );
      });
}

0 人点赞