今天的主题是,在flutter里面实现一个日期选择的自定义控件,或者说自定义组件,考虑到这个日期自定义组件的通用性,我们将会采用插件开发开始来做,这样就可以发布到 pub.dev 上,供广大flutter开发者用(虽然别人不一定会用哈,但是我们要对自己有一个小小的要求不是嘛!)
所以,读完本文,你讲学会两个大的知识点:
因为是操作实战,所以,我会给出完整的实现过程来,首先,我们确定的是需要创建一个自定义组件,并且需要发布到 pub.dev 上,因此,我们首先创建一个插件工程吧,可以参考这里。
flutter create --template=plugin --platforms=android,ios,linux,macos,windows date_picker
在Flutter中,创建自定义组件(也称为自定义widget)主要有三种方式:通过组合其他组件,自绘和实现RenderObject。
通过组合其他组件:这是创建自定义组件的最基本和最常见的方式。Flutter框架提供了大量的内置组件,如文本、图像、按钮等。你可以通过组合这些内置组件来创建自己的自定义组件。这种方式的优点是简单易用,适用于大多数场景。例如,你可以创建一个包含图像和文本的自定义按钮。
class CustomButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FlatButton(
onPressed: () {},
child: Row(
children: <Widget>[
Icon(Icons.add),
Text('Add'),
],
),
);
}
}
自绘:当内置组件无法满足你的需求时,你可以选择自绘。Flutter提供了CustomPaint和Canvas等类,你可以使用这些类来自定义绘制你的组件。这种方式的优点是灵活性高,可以绘制任何你想要的形状和样式。但是,这种方式的复杂度也较高,需要一定的绘图知识。例如,你可以创建一个自定义的进度条。
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,你可以完全控制组件的布局和绘制。这种方式的优点是最大的灵活性,但是复杂度也最高,通常只在创建高度自定义的组件或框架时使用。
要实现这个日期选择器,首先我们对需求进行分析之后,提炼出这些功能点
我们定义了一个 MonthView 组件来显示这个视图,其主要的功能就是渲染一个日历视图。其主要的逻辑在这段,在于怎么构造出一个 GridView
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();
}
这块逻辑做完,我们相当于完成了渲染部分了。
这部分就是按照规则来做,具体的代码很简单,下面也给出了注释
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;
});
}
当然,这部分的逻辑是是作者根据自己的思维模式来写的,可能和主流的日期选择有些差别。其主要的规则是
插件开发完毕,剩下的过程是发布了,首先你需要检查下有没有语法问题,使用以下命令来分析你的代码,确保没有任何语法错误:
flutter analyze
并运行测试:
flutter test
确保所有测试都通过,并且代码分析没有重要问题,我这里执行实际上是报错了的,但是修复起来也不是难事。
接下来才是真正的进入到发布环节,在发布之前,你需要在pub.dev上创建一个账户。然后,配置你的pubspec.yaml
文件,确保所有的信息都是最新的,包括版本号、描述、作者等。
使用以下命令来发布你的包:
flutter pub publish
这个命令会再次运行分析器,确保没有问题,并且会提示你确认发布的信息。
可以看看,我们亲手制作的插件,这里可以查看
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。