前往小程序,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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
基于WebGL的三维交通监控可视化技术应用(实践版) ThingJS
互联网技术为交通行业的可视化带来了多样性的发展。从传统的二维平面变形图、二维SVG矢量图到如今的SVG三维矢量技术、BIM技术、GIS+BIM技术、 WebGL技术,甚至连AR、VR、MR等虚拟现实技术,也开始应用于交通领域的可视化发展方面。
森友鹿锘
2020/12/14
1.8K0
基于WebGL的三维交通监控可视化技术应用(实践版) ThingJS
智慧园区系统建设技术方案
信息网络技术、安防技术等的发展已经比较成熟,因此,在本项目上技术要追求简便实用,设计及施工上要讲究成熟。
荷荷
2024/11/01
4530
2022爱分析· 地产科技厂商全景报告
地产科技,即房地产与科技的融合应用,是指利用人工智能、物联网、云计算、大数据、区块链、5G等数字化技术对房地产产业链上各环节进行业务流程重塑和模式创新,从而实现降本增效、消费者体验升级等价值。
爱分析ifenxi
2022/10/09
2.7K0
2022爱分析· 地产科技厂商全景报告
用于形状精确三维感知图像合成的着色引导生成隐式模型 | NeurIPS2021
编译 | 莓酊 编辑 | 青暮生成辐射场的发展推动了3D感知图像合成的发展。由于观察到3D对象从多个视点看起来十分逼真,这些方法引入了多视图约束作为正则化,以从2D图像学习有效的3D辐射场。尽管取得了进展,但由于形状-颜色的模糊性,它们往往无法捕获准确的3D形状,从而限制了在下游任务中的适用性。在这项研究工作中,来自马普所和港中文大学的学者通过提出一种新的着色引导生成隐式模型ShadeGAN来解决这种模糊性,它学习了一种改进的形状表示。 论文地址:https://arxiv.org/pdf/2110.15
AI科技评论
2022/03/03
7350
Unity3d场景快速烘焙【2020】
很多刚刚接触Unity3d的童鞋花了大量的时间自学,可总是把握不好Unity3d的烘焙,刚从一个坑里爬出来,又陷入另一个新的坑,每次烘焙一个场景少则几个小时,多则几十个小时,机器总是处于假死机状态,半天看不到结果,好不容易烘焙完了,黑斑、撕裂、硬边、漏光或漏阴影等缺陷遍布,惨不忍睹,整体效果暗无层次,或者苍白无力,灯光该亮的亮不起来,该暗的暗不下去,更谈不上有什么意境,痛苦的折磨,近乎失去了信心,一个团队从建模到程序,都没什么问题,可一到烘焙这一关,就堵得心塞,怎么也搞不出好的视觉效果,作品没法及时向用户交付,小姐姐在这里分享一些自己的经验,希望能帮到受此痛苦折磨的朋友,话不多说,开工!
全栈程序员站长
2022/07/01
4.4K0
Unity3d场景快速烘焙【2020】
基于EinScan-S软件的编码结构光方法空间三维模型重建
  上一篇文章基于3DSOM软件的侧影轮廓方法空间三维模型重建详细介绍了基于3DSOM的侧影轮廓方法物体空间三维模型重建;接下来,我们将在一款新的空间模型建立软件——EinScan-S中,完成一种新的空间三维模型重建方法——编码结构光方法。
疯狂学习GIS
2022/08/10
7630
基于EinScan-S软件的编码结构光方法空间三维模型重建
最新综述:深度学习图像三维重建最新方法及未来趋势
今天分享的是:深度学习领域基于图像的三维物体重建最新方法及未来趋势综述。原文:Image-based 3D Object Reconstruction: State-of-the-Art and Trends in the Deep Learning Era
小白学视觉
2022/09/28
7.6K0
最新综述 | 基于深度学习的SLAM方法:面向空间机器智能时代
A Survey on Deep Learning for Localization and Mapping Towards the Age of Spatial Machine Intelligence
用户1150922
2020/09/11
2.5K0
最新综述 | 基于深度学习的SLAM方法:面向空间机器智能时代
深度学习应用篇-计算机视觉-语义分割综述[5]:FCN、SegNet、Deeplab等分割算法、常用二维三维半立体数据集汇总、前景展望等
目前,计算机视觉是深度学习领域最热门的研究领域之一。从广义上来说,计算机视觉就是要“赋予机器自然视觉的能力”。实际上,计算机视觉本质上就是研究视觉感知问题,其目标就是对环境的表达和理解,核心问题是研究如何对输入的图像信息进行组织,对物体和场景进行识别,进而对图像内容给予解释。更进一步来说,计算机视觉就是研究如何让计算机利用摄像头等机器设备实现和人类一样“看”的能力,对目标进行分割、分类、识别、跟踪、判别决策。计算机视觉是一个跨领域的交叉学科,包括计算机科学(图形、算法、理论、系统、体系结构),数学(信息检索、机器学习),工程学(机器人、语音、自然语言处理、图像处理),物理学(光学 ),生物学(神经科学)和心理学(认知科学)等等。许多科学家认为,计算机视觉为人工智能的发展开拓了道路。
汀丶人工智能
2023/06/09
1.8K0
深度学习应用篇-计算机视觉-语义分割综述[5]:FCN、SegNet、Deeplab等分割算法、常用二维三维半立体数据集汇总、前景展望等
unity vr虚拟现实完全自学教程 pdf_ug80完全自学手册pdf
VR全称为Virtual Really,即虚拟现实:由计算机或独立计算单元生成虚拟环境,体验者通过封闭式的头部显示器(简称为头显)观看这些数字内容,虚拟现实设备通过传感器感知体验者的运动,将这些运动数据(例如头部的旋转,手部的移动等)传送给计算机,相应地改变数字环境内容,以符合体验者在现实世界的反应。体验者可以在虚拟环境中行走、观察,与物体进行交互,从而感受到与现实世界相似的体验。VR头显和耳机通过两种最突出的感官-视觉和听觉,实现了高品质的VR沉浸式体验。
全栈程序员站长
2022/10/04
4.1K0
unity vr虚拟现实完全自学教程 pdf_ug80完全自学手册pdf
深度学习背景下的图像三维重建技术进展综述
三维重建是指从单张二维图像或多张二维图像中重建出物体的三维模型,并对三维模型进行纹理映射的过程。三维重建可获取从任意视角观测并具有色彩纹理的三维模型,是计算机视觉领域的一个重要研究方向。传统的三维重建方法通常需要输入大量图像,并进行相机参数估计、密集点云重建、表面重建和纹理映射等多个步骤。近年来,深度学习背景下的图像三维重建受到了广泛关注,并表现出了优越的性能和发展前景。
一点人工一点智能
2023/01/07
6.6K0
深度学习背景下的图像三维重建技术进展综述
人脸识别长篇研究
人脸识别(Face Recognition)是一种依据人的面部特征(如统计或几何特征等),自动进行身份识别的一种生物识别技术,又称为面像识别、人像识别、相貌识别、面孔识别、面部识别等。通常我们所说的人脸识别是基于光学人脸图像的身份识别与验证的简称。
放飞人夜
2018/05/04
6.3K11
人脸识别长篇研究
3万字!体育馆智能化施工组织设计方案,文末附下载
本工程施工组织设计方案依据宣城市体育馆智能化系统工程招标书对宣城市体育馆智能化系统安装工程的要求、国家关于智能化系统施工安装标准与规范及本公司多年的智能化系统工程总承包的实施和管理经验而编写的。
网络技术联盟站
2023/03/13
6990
3万字!体育馆智能化施工组织设计方案,文末附下载
计算机视觉学术速递[8.30]
【1】 Evaluating Transformer based Semantic Segmentation Networks for Pathological Image Segmentation 标题:基于Transformer的语义分割网络在病理图像分割中的评价 链接:https://arxiv.org/abs/2108.11993
公众号-arXiv每日学术速递
2021/09/16
7650
计算机视觉与模式识别学术速递[12.16]
【1】 Vision Transformer Based Video Hashing Retrieval for Tracing the Source of Fake Videos 标题:基于视觉变换的视频散列检索追查假视频来源 链接:https://arxiv.org/abs/2112.08117
公众号-arXiv每日学术速递
2021/12/17
1.2K0
计算机视觉与模式识别学术速递[11.11]
【1】 Multimodal Transformer with Variable-length Memory for Vision-and-Language Navigation 标题:用于视觉和语言导航的变长记忆多模转换器 链接:https://arxiv.org/abs/2111.05759
公众号-arXiv每日学术速递
2021/11/17
1K0
计算机视觉学术速递[8.19]
【1】 Boosting Salient Object Detection with Transformer-based Asymmetric Bilateral U-Net 标题:基于Transformer的非对称双边U网增强显著目标检测 链接:https://arxiv.org/abs/2108.07851
公众号-arXiv每日学术速递
2021/08/24
1.7K0
计算机视觉学术速递[8.23]
【1】 Trans4Trans: Efficient Transformer for Transparent Object and Semantic Scene Segmentation in Real-World Navigation Assistance 标题:Trans4Trans:真实导航辅助中透明对象和语义场景分割的高效转换器 链接:https://arxiv.org/abs/2108.09174
公众号-arXiv每日学术速递
2021/08/24
2K0
计算机视觉与模式识别学术速递[12.24]
【1】 ELSA: Enhanced Local Self-Attention for Vision Transformer 标题:ELSA:增强视觉转换器的局部自我注意 链接:https://arxiv.org/abs/2112.12786
公众号-arXiv每日学术速递
2021/12/27
1.4K0
30分钟了解所有引擎组件,132个Unity 游戏引擎组件速通!【收藏 == 学会】
Mesh Filter 组件包含对网格的引用。该组件与同一个游戏对象上的 Mesh Renderer 组件配合使用;Mesh Renderer 组件渲染 Mesh Filter 组件引用的网格。
呆呆敲代码的小Y
2023/07/05
3.4K0
30分钟了解所有引擎组件,132个Unity 游戏引擎组件速通!【收藏 == 学会】
推荐阅读
相关推荐
基于WebGL的三维交通监控可视化技术应用(实践版) ThingJS
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验