Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Flutter 仿ios自定义一个DatePicker

Flutter 仿ios自定义一个DatePicker

作者头像
赵哥窟
发布于 2021-03-02 06:32:36
发布于 2021-03-02 06:32:36
1.1K00
代码可运行
举报
文章被收录于专栏:日常技术分享日常技术分享
运行总次数:0
代码可运行

Screenshot_1612747215.png

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
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);
          },
        );
      });
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Windows下完全卸载node.js并安装node.js的多版本管理工具nvm-windows
由于高版本的node.js导致gulp执行build命令失败,我需要在Windows下卸载掉已有的node.js并安装一个多版本管理工具nvm-windows,方便切换不同版本的node.js。
雨临Lewis
2022/01/11
3.2K0
NodeJs——nvm安装和使用
今天要编译一个其他nodejs版本的程序,然后就去github找找看看是不是有相应的nodejs版本管理工具,然后就找到了!
思索
2024/08/16
1690
NodeJs——nvm安装和使用
如何在Linux上安装Node.js
版权声明:本文为木偶人shaon原创文章,转载请注明原文地址,非常感谢。 https://blog.csdn.net/wh211212/article/details/53039286
shaonbean
2019/05/26
2.4K0
NVM管理多版本Node.js教程
Node Version Manager(NVM)是一个用于管理多个Node.js版本的工具。它允许用户在同一台机器上安装和使用多个Node.js版本,非常适合需要同时进行多个项目的开发者。NVM是开源的,支持MacOS、Windows和Linux操作系统。
Damon小智
2024/05/05
4.2K7
NVM管理多版本Node.js教程
【2023最新版】Win11使用nvm-windows版本管理工具安装Node.js(或直接安装)+在Webstorm中使用(本地运行AI 代码翻译器项目)
(推荐使用nvm-windows版本管理工具安装Node.js,亦可选择如下直接安装)
Qomolangma
2024/07/29
4810
【2023最新版】Win11使用nvm-windows版本管理工具安装Node.js(或直接安装)+在Webstorm中使用(本地运行AI 代码翻译器项目)
Mac下nvm管理node.js版本问题
本篇文章主要是针对已经安装了node.js和nvm管理工具小伙伴遇到的问题。 管理工具有两个,一个是nvm,还有一个是n nvm的好处就是可以管理多个node版本,而且可以切换想要的版本,可以安装一个稳定版和最高版, nvm管理语句:  使用nvm安装node $ nvm ls-remote 查看 所有的node可用版本 $ nvm install xxx 下载你想要的版本 $ nvm use xxx 使用指定版本的node  $ nvm alias default xxx 每次启动终端都使
cMusketeer
2018/03/28
3K0
Windows 中 Node.js 中 nvm 的安装配置和使用
可以访问下面的地址来找到最新的 nvm 的安装版本: Releases · coreybutler/nvm-windows · GitHub
HoneyMoose
2021/08/11
1.1K0
Windows 中 Node.js 中 nvm 的安装配置和使用
NVM-Windows – Windows随意切换node版本 – 开源项目
在Windows上安装Node.js环境并实现版本切换,通常可以使用nvm-windows(Node Version Manager for Windows)。以下是详细步骤:
收心
2024/11/20
6180
Windows下安装及使用NVM
我们可能同时在进行2个或者多个项目,而不同的项目所使用的node版本有可能是不一样的,再或者要用最新的node版本进行试验和学习。在这种情况下,对于维护多个版本的node将会是一件非常麻烦的事情,而nvm就是为解决这个问题而产生的,它可以方便的在同一台设备上进行多个node版本之间切换,而这个正是nvm的价值所在,详细信息可以在nvm官网查看。
青年码农
2020/10/13
1.9K0
Windows下安装及使用NVM
怎样切换不同版本的 Node[每日前端夜话0x90]
有时候几乎每周都会发布新版本的 Node.js —— 每隔几周发布一次小版本,每隔几个月发布一次主要版本。如果你是一个需要在不同程序和项目之间切换的码农,可能会发现需要运行不同版本的 Node。
疯狂的技术宅
2019/07/10
4.4K0
怎样切换不同版本的 Node[每日前端夜话0x90]
三种方式轻松搭建 Node.js
在 企业开发中,我们通常选择长期稳定版的 Node.js,因为它意味着 更少的 BUG、更加可靠的运行环境(LTS 最新版本,推荐用于生产环境)。
程序员NEO
2025/04/09
2200
三种方式轻松搭建 Node.js
Windows环境下 NVM 介绍、下载安装及使用详解
Node.js是一种基于Chrome V8引擎的JavaScript运行时,可以让JavaScript在服务器端运行,从而实现了前后端代码共用。但是,不同版本的Node.js可能会有差异,这就需要我们使用版本管理工具来方便地切换版本。而NVM (Node Version Manager)就是一款非常好用的Node.js版本管理工具,它可以轻松地在不同的Node.js版本之间切换。
Yeats_Liao
2023/12/07
4.6K3
如何在Ubuntu 16.04上安装Node.js
Node.js是一个用于通用编程的JavaScript平台,允许用户快速构建网络应用程序。通过在前端和后端利用JavaScript,开发可以更加一致并在同一系统中进行设计。
angel_郁
2018/10/10
7.4K1
使用 nvm 管理 node 版本:如何在 macOS 和 Windows 上安装使用nvm
在开发 JavaScript 应用时,node 是一个重要的运行环境,而 nvm(Node Version Manager)是管理node版本的利器。
空白诗
2024/09/16
2K0
使用 nvm 管理 node 版本:如何在 macOS 和 Windows 上安装使用nvm
三种方法在CVM安装Node.js
Node.js是一个用于通用编程的JavaScript平台,允许用户快速构建网络应用程序。通过在前端和后端利用JavaScript,Node.js使开发更加一致和集成。
吴凌云
2018/07/13
3.5K0
nvm----nodejs版本管理工具!
nvm全英文也叫node.js version management,是一个nodejs的版本管理工具。nvm和n都是node.js版本管理工具,为了解决node.js各种版本存在不兼容现象可以通过它可以安装和切换不同版本的node.js。
科控物联
2024/03/20
7360
nvm----nodejs版本管理工具!
如何在CentOS Linux 7.5上安装Node.js
本教程将引导您在CentOS Linux 7.5机器上安装Node.js和npm。 Node.js是一个跨平台的JavaScript运行时环境,允许服务器端执行JavaScript代码。 Node.js主要用于后端,但它也是一种全栈和前端解决方案。 npm是Node.js的默认包管理器。
知忆
2021/06/11
1.6K0
01安装nvm及js基础语法
下载地址:https://github.com/coreybutler/nvm-windows/releases
Dreamy.TZK
2020/04/09
1.7K0
使用nvm管理node版本,切换node版本
https://github.com/coreybutler/nvm-windows/releases
用户10106350
2022/10/28
1.9K0
[Node] nvm 安装 node 和 npm
可以使用 command 或者 git-bash 运行。(注意: nvm use 命令必须要以管理员身份运行)
绿巨人
2021/11/08
4K0
相关推荐
Windows下完全卸载node.js并安装node.js的多版本管理工具nvm-windows
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验