Flutter分页垂直日历插件paged_vertical_calendar的使用
Flutter分页垂直日历插件paged_vertical_calendar的使用
📆 Paged Vertical Calendar 📆
paged_vertical_calendar
是一个用于实现基于日历界面的简单分页框架。
🔨 工作原理
paged_vertical_calendar
是一个非常简约的框架,它会根据滚动行为自动加载月份。它提供了许多有用的回调函数来实现自定义的日历交互,并提供构建器来自定义日历外观。请查看示例以了解日期范围选择和分页数据可视化的几种实现方式。
PagedVerticalCalendar
没有必需的参数,只要提供固定的高度即可使用。
Scaffold(
body: PagedVerticalCalendar(),
);
📢 功能
以下是 PagedVerticalCalendar
提供的一些功能:
PagedVerticalCalendar(
minDate: DateTime.now().subtract(Duration(days: 365)),
maxDate: DateTime.now().add(Duration(days: 365)),
initialDate: DateTime.now().add(Duration(days: 3)),
invisibleMonthsThreshold: 1,
startWeekWithSunday: true,
onMonthLoaded: (year, month) {
// 当月加载时触发
},
onDayPressed: (value) {
// 当点击某天时触发
},
onPaginationCompleted: (direction) {
// 分页完成时触发
},
);
onMonthLoaded
: 每当添加一个月到列表时触发此回调。可以通过设置invisibleMonthsThreshold
参数来调整触发时间。invisibleMonthsThreshold
: 决定在视图外应加载多少个月份。换句话说,用户滚动到该位置之前应预加载多少个月份,默认值为1
。onDayPressed
: 简单的onPressed
回调,同时提供被点击日期的DateTime
。startWeekWithSunday
: 如果应用程序针对周日开始的国家/地区进行本地化,可以将此参数设置为true
。minDate
: 提供最小日期后,日历将在该日期停止向上滚动。确保minDate
<maxDate
。maxDate
: 提供最大日期后,日历将在该日期停止向下滚动。确保maxDate
>minDate
。initialDate
: 提供初始日期后,日历将从该日期开始显示(否则为DateTime.now()
)。确保minDate
<initialData
<maxDate
。onPaginationCompleted
: 当提供minDate
或maxDate
时,此回调会在分页完成后触发,并返回PaginationDirection
以指示达到日历的哪一侧。
🎨 自定义
PagedVerticalCalendar
提供默认的日历样式,但这些样式可以完全自定义。为此,提供了多个构建器:
PagedVerticalCalendar(
monthBuilder: (context, month, year) {
// 提供一个月份标题小部件
},
dayBuilder: (context, date) {
// 提供一个日期小部件
},
listPadding: // 提供 EdgeInset 值
);
monthBuilder
: 提供年份和月份作为整数。此构建器必须返回一个形成每月标题的小部件,intl
包在这里用于日期格式化效果很好。dayBuilder
: 提供日期作为DateTime
。此构建器将为每一天调用一次。通常至少需要提供一个包含当前日期编号的文本小部件。listPadding
: 可以提供边距以确保列表具有内边距。
👋 参与其中
如果这个包对你有用,请在 pub.dev 上点赞并在 GitHub 上加星。如果你有任何问题、建议或拉取请求,我非常愿意看到它们!
示例代码
以下是一个完整的示例代码,展示了如何使用 paged_vertical_calendar
实现自定义日历、日期选择器和分页数据展示。
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:paged_vertical_calendar/paged_vertical_calendar.dart';
void main() => runApp(Home());
/// 一个简单的例子,展示了如何使用此包实现日历相关界面。
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) => MaterialApp(
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
title: const Text('Paged Vertical Calendar'),
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.label,
tabs: [
Tab(icon: Icon(Icons.calendar_today), text: 'Custom'),
Tab(icon: Icon(Icons.date_range), text: 'DatePicker'),
Tab(icon: Icon(Icons.dns), text: 'Pagination'),
],
),
),
body: TabBarView(
children: [
Custom(),
DatePicker(),
Pagination(),
],
),
),
),
);
}
/// 展示日历可定制性的简单示例。
class Custom extends StatelessWidget {
@override
Widget build(BuildContext context) {
return PagedVerticalCalendar(
startWeekWithSunday: true,
/// 自定义月份头部外观,添加一周指示器。
monthBuilder: (context, month, year) {
return Column(
children: [
/// 创建一个自定义标题,显示月份和年份。
Container(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 20),
margin: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.all(Radius.circular(50)),
),
child: Text(
DateFormat('MMMM yyyy').format(DateTime(year, month)),
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
color: Colors.white,
),
),
),
/// 添加一行显示星期几。
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
weekText('Su'),
weekText('Mo'),
weekText('Tu'),
weekText('We'),
weekText('Th'),
weekText('Fr'),
weekText('Sa'),
],
),
),
],
);
},
/// 在每周之间添加一条线。
dayBuilder: (context, date) {
return Column(
children: [
Text(DateFormat('d').format(date)),
const Divider(),
],
);
},
);
}
Widget weekText(String text) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
text,
style: TextStyle(color: Colors.grey, fontSize: 10),
),
);
}
}
/// 显示如何制作基本的日期范围选择器并带有UI指示。
class DatePicker extends StatefulWidget {
@override
_DatePickerState createState() => _DatePickerState();
}
class _DatePickerState extends State<DatePicker> {
/// 存储选中的开始和结束日期。
DateTime? start;
DateTime? end;
/// 方法用于检查某天是否在选中范围内,用于高亮显示。
bool isInRange(DateTime date) {
if (start == null) return false;
if (end == null) return date == start;
return ((date == start || date.isAfter(start!)) &&
(date == end || date.isBefore(end!)));
}
@override
Widget build(BuildContext context) {
return PagedVerticalCalendar(
addAutomaticKeepAlives: true,
dayBuilder: (context, date) {
final color = isInRange(date) ? Colors.green : Colors.transparent;
return Container(
color: color,
child: Center(
child: Text(DateFormat('d').format(date)),
),
);
},
onDayPressed: (date) {
setState(() {
if (start == null)
start = date;
else if (end == null)
end = date;
else {
print('selected range from $start to $end');
start = null;
end = null;
}
});
},
);
}
}
/// 显示如何在日历中显示分页数据并与之交互。
class Pagination extends StatefulWidget {
@override
_PaginationState createState() => _PaginationState();
}
class _PaginationState extends State<Pagination> {
/// 存储所有要显示的项目。
List<DateTime> items = [];
/// 每次加载新月份时调用。
void fetchNewEvents(int year, int month) async {
Random random = Random();
final newItems = List<DateTime>.generate(random.nextInt(40), (i) {
return DateTime(year, month, random.nextInt(27) + 1);
});
setState(() => items.addAll(newItems));
}
@override
Widget build(BuildContext context) {
return PagedVerticalCalendar(
addAutomaticKeepAlives: true,
onMonthLoaded: fetchNewEvents,
dayBuilder: (context, date) {
final eventsThisDay = items.where((e) => e == date);
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(DateFormat('d').format(date)),
Wrap(
children: eventsThisDay.map((event) {
return Padding(
padding: const EdgeInsets.all(1),
child: CircleAvatar(
radius: 5,
backgroundColor: Colors.red,
),
);
}).toList(),
)
],
);
},
onDayPressed: (day) {
final eventsThisDay = items.where((e) => e == day);
print('items this day: $eventsThisDay');
},
);
}
}
希望这段内容能帮助你更好地理解和使用 paged_vertical_calendar
插件!如果有任何问题或需要进一步的帮助,请随时提问。
更多关于Flutter分页垂直日历插件paged_vertical_calendar的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
1 回复