前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于Flutter手把手教你实现一个日期选择(日历形式)

基于Flutter手把手教你实现一个日期选择(日历形式)

原创
作者头像
brzhang
修改2023-11-14 20:26:27
1.4K0
修改2023-11-14 20:26:27
举报
文章被收录于专栏:玩转全栈玩转全栈

今天的主题是,在flutter里面实现一个日期选择的自定义控件,或者说自定义组件,考虑到这个日期自定义组件的通用性,我们将会采用插件开发开始来做,这样就可以发布到 pub.dev 上,供广大flutter开发者用(虽然别人不一定会用哈,但是我们要对自己有一个小小的要求不是嘛!)

所以,读完本文,你讲学会两个大的知识点:

  • 如何在flutter上做一个自定义组件
  • 如何开发插件并发布到 pub.dev

因为是操作实战,所以,我会给出完整的实现过程来,首先,我们确定的是需要创建一个自定义组件,并且需要发布到 pub.dev 上,因此,我们首先创建一个插件工程吧,可以参考这里

代码语言:javascript
复制
flutter create --template=plugin --platforms=android,ios,linux,macos,windows date_picker

在flutter种创建自定义组件的三种方式介绍

在Flutter中,创建自定义组件(也称为自定义widget)主要有三种方式:通过组合其他组件,自绘和实现RenderObject。

通过组合其他组件:这是创建自定义组件的最基本和最常见的方式。Flutter框架提供了大量的内置组件,如文本、图像、按钮等。你可以通过组合这些内置组件来创建自己的自定义组件。这种方式的优点是简单易用,适用于大多数场景。例如,你可以创建一个包含图像和文本的自定义按钮。

代码语言:javascript
复制
class CustomButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FlatButton(
      onPressed: () {},
      child: Row(
        children: <Widget>[
          Icon(Icons.add),
          Text('Add'),
        ],
      ),
    );
  }
}

自绘:当内置组件无法满足你的需求时,你可以选择自绘。Flutter提供了CustomPaint和Canvas等类,你可以使用这些类来自定义绘制你的组件。这种方式的优点是灵活性高,可以绘制任何你想要的形状和样式。但是,这种方式的复杂度也较高,需要一定的绘图知识。例如,你可以创建一个自定义的进度条。

代码语言:javascript
复制
class CustomProgressBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: _ProgressBarPainter(),
    );
  }
}

class _ProgressBarPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
// 绘制进度条
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

实现RenderObject:这是创建自定义组件的最底层方式。Flutter的渲染系统是基于RenderObject的,每个组件都对应一个RenderObject。通过实现自己的RenderObject,你可以完全控制组件的布局和绘制。这种方式的优点是最大的灵活性,但是复杂度也最高,通常只在创建高度自定义的组件或框架时使用。

使用内置组件组合的方式实现一个日期选择器

要实现这个日期选择器,首先我们对需求进行分析之后,提炼出这些功能点

  • 需要有一个日历展示视图来讲日期已日历的方式渲染出来
  • 需要有一个向左向右的切换按钮方便快速切换到下一个月,上一个月
  • 需要有一个label展示当前展示的日历在何年何月
  • 简单起见,设置初始化时默认选择的区间开始,区间结束都是当天
  • 编写区间选中规则,具体可以看下面的流程图

  • 还要考虑选中部分的渲染,既如何标记区分出选中的。

如何渲染出日历展示的日期选择视图

我们定义了一个 MonthView 组件来显示这个视图,其主要的功能就是渲染一个日历视图。其主要的逻辑在这段,在于怎么构造出一个 GridView

代码语言:javascript
复制
List<Widget> dayTiles = [];
    for (int i = 0; i < firstWeekdayOfMonth - 1; i++) {
      dayTiles.add(Container()); // empty days to align the first day
    }

    for (int i = 1; i <= daysInMonth; i++) {
      final day = DateTime(month.year, month.month, i);
      final isSelected =
          (day.isAfter(selectedStartDate.subtract(Duration(days: 1))) &&
                  day.isBefore(selectedEndDate.add(Duration(days: 1)))) ||
              day == selectedStartDate ||
              day == selectedEndDate;

      BoxDecoration decoration;
      if (isSelected) {
        decoration = BoxDecoration(
          color: Theme.of(context).primaryColor,
          shape: BoxShape.circle,
        );
      } else {
        decoration = BoxDecoration();
      }
  • 这里按照每行7天的方式显示,因为是日历呈现嘛
  • 找到本月种周的第一天所在,它前面的补空格展示
  • 然后讲剩下的天数都显示出来
  • 以及,我们后面要应对的选中的区域着色的逻辑。

这块逻辑做完,我们相当于完成了渲染部分了。

完成日期的选择逻辑

这部分就是按照规则来做,具体的代码很简单,下面也给出了注释

代码语言:javascript
复制
void _onDateSelected(DateTime selectedDate) {
    setState(() {
      // 如果没有选中的结束日期,或者选中的开始日期晚于当前选中的日期
      if (selectedDate.isBefore(_selectedStartDate)) {
        //比最左区间日期还小
        _selectedStartDate = selectedDate;
      } else if (selectedDate.isAfter(_selectedEndDate)) {
        //比有区间日期还大
        _selectedEndDate = selectedDate;
      } else {
        // 处在了区间内,将 selectedDate 与 _lastSelectedDate 比较,小的给到 _selectedStartDate,大的给到 _selectedEndDate
        if (selectedDate.isAfter(_lastSelectedDate)) {
          _selectedEndDate = selectedDate;
          _selectedStartDate = _lastSelectedDate;
        } else {
          _selectedStartDate = selectedDate;
          _selectedEndDate = _lastSelectedDate;
        }
      }
      widget.onDateRangeSelected([_selectedStartDate, _selectedEndDate]);
      _lastSelectedDate = selectedDate;
    });
  }

当然,这部分的逻辑是是作者根据自己的思维模式来写的,可能和主流的日期选择有些差别。其主要的规则是

  • 初始化是选中的是当天,类似于用户选择的的起始日期和终止日期是同一天及当天。
  • 当用户点击一个日期时,此时判断,如果在起始日期之前,就将起始日期设置为当前选中的日期
  • 如果在终止日期之后,就将终止日期设置为当前选中的日期
  • 如果在区间内呢?这时候我们记录的最后一次的用户点击日期就发挥作用了,此时对selectedDate和_lastSelectedDate进行比较,小的给到起始日期,大的给到终止日期。。

如何发布

插件开发完毕,剩下的过程是发布了,首先你需要检查下有没有语法问题,使用以下命令来分析你的代码,确保没有任何语法错误:

代码语言:javascript
复制
flutter analyze

并运行测试:

代码语言:javascript
复制
flutter test

确保所有测试都通过,并且代码分析没有重要问题,我这里执行实际上是报错了的,但是修复起来也不是难事。

接下来才是真正的进入到发布环节,在发布之前,你需要在pub.dev上创建一个账户。然后,配置你的pubspec.yaml文件,确保所有的信息都是最新的,包括版本号、描述、作者等。

使用以下命令来发布你的包:

代码语言:javascript
复制
flutter pub publish

这个命令会再次运行分析器,确保没有问题,并且会提示你确认发布的信息。

可以看看,我们亲手制作的插件,这里可以查看

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 在flutter种创建自定义组件的三种方式介绍
  • 使用内置组件组合的方式实现一个日期选择器
  • 如何渲染出日历展示的日期选择视图
  • 完成日期的选择逻辑
  • 如何发布
相关产品与服务
腾讯云代码分析
腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com