Flutter活动日历管理插件activity_calendar的使用
Flutter活动日历管理插件activity_calendar的使用
activity_calendar
是一个类似 Github 的活动日历小部件。它允许用户自定义视图,并为每个项目添加可选的提示信息和点击监听器。
特性
- 支持任意天数的活动日历
- 可定制视图
- 每个项目可选的提示信息
- 每个项目可选的点击监听器
使用方法
要使用 ActivityCalendar
,你需要推送一个表示每天活动数量的 List<int>
。
ActivityCalendar(
activities: activities,
)
ActivityCalendar
还有一些参数可以用来自定义其视图。
提示信息
你可以通过传递 TooltipBuilder? tooltipBuilder
参数来为每个项目添加提示信息。
TooltipBuilder.text(
builder: (int i) => '${activities[i]} 贡献',
textStyle: TextStyle(fontWeight: FontWeight.bold),
);
TooltipBuilder.rich(
builder: (int i) => TextSpan(
children: [
TextSpan(
text: '${activities[i]} 贡献',
style: TextStyle(fontWeight: FontWeight.bold),
),
TextSpan(
text: ' on ${calculateDate(i)}',
),
],
),
);
示例代码
以下是一个完整的示例代码,展示了如何使用 activity_calendar
插件。
import 'dart:math';
import 'package:activity_calendar/activity_calendar.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
void main() {
runApp(const ExampleApp());
}
/// 数据
final _random = Random();
List<int> _randomActivities([int length = 365, int max = 10]) =>
List.generate(length, (index) => _random.nextInt(max));
final List<int> _activities = _randomActivities(1000, 10);
final DateFormat _weekdayFormat = DateFormat.E();
final DateFormat _tooltipFormat = DateFormat.MMMEd();
/// 星期几的名字,从周一到周日
final List<String> _weekdays =
List.generate(7, (i) => _weekdayFormat.format(DateTime(2000, 0, 6 + i)));
/// 应用程序
class ExampleApp extends StatelessWidget {
const ExampleApp({Key? key}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Activity Calendar Example',
themeMode: ThemeMode.dark,
darkTheme: ThemeData.dark(),
home: Builder(
builder: (context) => Scaffold(
appBar: AppBar(
title: const Text('Activity Calendar Example'),
backgroundColor: Colors.grey[850],
elevation: 3,
centerTitle: false,
actions: [
IconButton(
icon: Icon(Icons.adaptive.more),
onPressed: () => _showSettings(context: context),
),
],
bottom: PreferredSize(
preferredSize: const Size.fromHeight(24),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: Align(
alignment: Alignment.topRight,
child: Wrap(
spacing: 4,
runAlignment: WrapAlignment.start,
alignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
const Text('Less'),
...ActivityCalendar.tiles(
_sharedFromColor(context),
_sharedToColor(context),
5,
5,
const BorderRadius.all(Radius.circular(4)),
).values.map((e) => SizedBox(
width: 24,
height: 24,
child: e,
)),
const Text('More'),
],
),
),
),
),
),
body: _Body(),
),
),
);
}
}
class _Body extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
final today = DateTime.now();
String calculateDate(int i) =>
_tooltipFormat.format(today.subtract(Duration(days: i)));
final orientation = _sharedOrientation(context);
final isVertical = orientation == Axis.vertical;
final calendar = ActivityCalendar(
activities: _activities.sublist(0, _sharedDaysCount(context)),
fromColor: _sharedFromColor(context),
toColor: _sharedToColor(context),
steps: 5,
borderRadius: BorderRadius.circular(4),
weekday: _sharedWeekday(context),
scrollDirection: _sharedOrientation(context),
reverse: _sharedOrientation(context) == Axis.horizontal,
tooltipBuilder: TooltipBuilder.rich(
builder: (i) => TextSpan(children: [
TextSpan(
text: '${_activities[i]} 贡献',
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
TextSpan(text: ' on ${calculateDate(i)}'),
]),
),
);
if (isVertical) {
return Column(
children: [
Row(
children: [
for (final weekday in _weekdays)
Expanded(
child: Center(
child: Text(
weekday,
textAlign: TextAlign.center,
),
),
),
],
),
Expanded(
child: calendar,
),
],
);
}
return SizedBox(
height: 200,
child: Row(
children: [
Column(
children: [
for (final weekday in _weekdays)
Expanded(
child: Center(
child: Text(
weekday,
textAlign: TextAlign.center,
),
),
),
],
),
Expanded(
child: calendar,
),
],
),
);
}
}
/// 共享应用程序数据部分
final Object _fromColorKey = Object();
final Object _toColorKey = Object();
final Object _daysCountKey = Object();
final Object _weekdayKey = Object();
final Object _orientationKey = Object();
Color _sharedFromColor(BuildContext context) =>
SharedAppData.getValue<Object, Color>(
context,
_fromColorKey,
() => Theme.of(context).colorScheme.surface,
);
Color _sharedToColor(BuildContext context) =>
SharedAppData.getValue<Object, Color>(
context,
_toColorKey,
() => Theme.of(context).colorScheme.primary,
);
int _sharedDaysCount(BuildContext context) => SharedAppData.getValue(
context,
_daysCountKey,
() => 365,
);
int _sharedWeekday(BuildContext context) => SharedAppData.getValue(
context,
_weekdayKey,
() => DateTime.now().weekday,
);
Axis _sharedOrientation(BuildContext context) => SharedAppData.getValue(
context,
_orientationKey,
() => Axis.vertical,
);
/// 有用的部件
class _ColorMenuItem extends StatelessWidget {
final VoidCallback onTap;
final Color color;
final String title;
const _ColorMenuItem({
Key? key,
required this.onTap,
required this.color,
required this.title,
}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return ListTile(
title: Text(title),
onTap: onTap,
trailing: _ColorWidget(color: color),
tileColor: color.withOpacity(0.2),
);
}
}
class _ColorWidget extends StatelessWidget {
final Color color;
const _ColorWidget({
Key? key,
required this.color,
}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return Container(
width: 32,
height: 32,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: color,
),
);
}
}
/// 对话框
Future<Color?> _selectColor({
required BuildContext context,
}) =>
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Pick a color'),
content: SizedBox(
width: double.maxFinite,
child: GridView.count(
crossAxisCount: 5,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: [
Colors.red,
Colors.pink,
Colors.purple,
Colors.deepPurple,
Colors.indigo,
Colors.blue,
Colors.lightBlue,
Colors.cyan,
Colors.teal,
Colors.green,
Colors.lightGreen,
Colors.lime,
Colors.yellowAccent,
Colors.yellow,
Colors.amber,
Colors.orange,
Colors.deepOrange,
Colors.brown,
Colors.grey,
Colors.blueGrey,
Colors.black,
Colors.white,
]
.map((color) => InkResponse(
onTap: () => Navigator.of(context).pop(color),
child: _ColorWidget(color: color),
))
.toList(),
),
),
),
);
Future<void> _showSettings({required BuildContext context}) =>
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: Text(
'Settings',
style: Theme.of(context).textTheme.headline6,
),
),
const Divider(
height: 1,
indent: 8,
endIndent: 8,
),
_ColorMenuItem(
title: 'Color from',
onTap: () async {
final color = await _selectColor(context: context);
if (color != null) {
SharedAppData.setValue(
context,
_fromColorKey,
color,
);
}
},
color: _sharedFromColor(context),
),
_ColorMenuItem(
title: 'Color to',
onTap: () async {
final color = await _selectColor(context: context);
if (color != null) {
SharedAppData.setValue(
context,
_toColorKey,
color,
);
}
},
color: _sharedToColor(context),
),
ListTile(
title: const Text('Days count'),
trailing: DropdownButtonHideUnderline(
child: DropdownButton<int>(
value: _sharedDaysCount(context),
items: const [
DropdownMenuItem(child: Text('1'), value: 1),
DropdownMenuItem(child: Text('7'), value: 7),
DropdownMenuItem(child: Text('30'), value: 30),
DropdownMenuItem(child: Text('365'), value: 365),
DropdownMenuItem(child: Text('1000'), value: 1000),
],
onChanged: (value) => SharedAppData.setValue(
context,
_daysCountKey,
value,
),
),
),
),
ListTile(
title: const Text('Weekday'),
trailing: DropdownButtonHideUnderline(
child: DropdownButton<int>(
value: _sharedWeekday(context),
items: [
for (int i = 0; i < _weekdays.length; i++)
DropdownMenuItem(
value: i + 1,
child: Text(_weekdays[i]),
),
],
onChanged: (value) => SharedAppData.setValue(
context,
_weekdayKey,
value,
),
),
),
),
ListTile(
title: const Text('Orientation'),
trailing: DropdownButtonHideUnderline(
child: DropdownButton<Axis>(
value: _sharedOrientation(context),
items: [
for (final axis in Axis.values)
DropdownMenuItem(
value: axis,
child: Text(axis.toString()),
),
],
onChanged: (value) => SharedAppData.setValue(
context,
_orientationKey,
value,
),
),
),
)
],
),
);
更多关于Flutter活动日历管理插件activity_calendar的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter活动日历管理插件activity_calendar的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用activity_calendar
插件来管理活动日历的一个基本示例。activity_calendar
插件允许你展示和管理日历中的活动。请注意,由于具体的插件API和实现可能会随着时间变化,以下代码可能需要根据实际插件版本进行调整。
首先,确保你的Flutter项目中已经添加了activity_calendar
插件。在你的pubspec.yaml
文件中添加以下依赖:
dependencies:
flutter:
sdk: flutter
activity_calendar: ^最新版本号 # 替换为插件的实际最新版本号
然后运行flutter pub get
来安装插件。
接下来是一个简单的示例代码,展示如何使用activity_calendar
插件来显示和管理日历活动:
import 'package:flutter/material.dart';
import 'package:activity_calendar/activity_calendar.dart'; // 导入插件
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Activity Calendar Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
ActivityCalendarController _controller;
@override
void initState() {
super.initState();
// 初始化ActivityCalendarController
_controller = ActivityCalendarController(
initialSelectedDate: DateTime.now(),
// 设置其他初始化参数,如活动数据等
);
// 添加一些示例活动
_addSampleActivities();
}
@override
void dispose() {
_controller.dispose(); // 释放资源
super.dispose();
}
void _addSampleActivities() {
// 添加活动示例
_controller.addEvent(
Activity(
title: 'Event 1',
date: DateTime(2023, 10, 1),
color: Colors.red,
),
);
_controller.addEvent(
Activity(
title: 'Event 2',
date: DateTime(2023, 10, 5),
color: Colors.blue,
),
);
// 可以继续添加更多活动
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Activity Calendar Demo'),
),
body: ActivityCalendar(
controller: _controller,
onDaySelected: (date) {
// 用户选择日期时的回调
print('Selected date: $date');
},
// 其他可选参数,如事件点击回调等
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// 打开添加活动的页面或逻辑
// 这里可以弹出一个对话框让用户输入活动详情
},
tooltip: 'Add Event',
child: Icon(Icons.add),
),
);
}
}
// 定义活动类(假设插件没有自带此类,根据实际情况调整)
class Activity {
final String title;
final DateTime date;
final Color color;
Activity({required this.title, required this.date, required this.color});
}
注意:
- 上述代码中的
Activity
类是一个假设的类,用于存储活动信息。实际使用时,请根据activity_calendar
插件的文档调整。 ActivityCalendarController
和ActivityCalendar
也是假设的类名,用于演示如何初始化和管理日历。请查阅activity_calendar
插件的官方文档获取正确的类名和使用方法。- 插件的API可能会随版本更新而变化,请参考最新的官方文档进行开发。
希望这个示例能帮助你开始在Flutter项目中使用activity_calendar
插件。如果有任何问题或需要进一步的帮助,请查阅插件的官方文档或提出具体问题。