Flutter & OpenHarmony OA系统日程日历组件开发指南

前言
日程管理是OA办公系统中不可或缺的功能模块,它帮助员工合理安排工作时间、记录重要会议、设置任务提醒。日历组件作为日程管理的核心界面,需要直观地展示每日、每周、每月的日程安排,支持快速切换视图、添加日程、查看详情等操作。本文将深入讲解如何使用Flutter和OpenHarmony开发一个功能丰富的日程日历组件。
组件功能规划
日程日历组件需要支持三种视图模式:月视图用于查看整月日程概览,周视图用于查看一周的详细安排,日视图用于查看单日的时间线。组件还需要支持日程的增删改查操作,以及与后端服务的数据同步。在视觉设计上,有日程的日期需要有明显标识,不同类型的日程用不同颜色区分。
Flutter端实现
定义日程数据模型:
class ScheduleEvent {
final String id;
final String title;
final String description;
final DateTime startTime;
final DateTime endTime;
final Color color;
final bool isAllDay;
ScheduleEvent({
required this.id,
required this.title,
this.description = '',
required this.startTime,
required this.endTime,
required this.color,
this.isAllDay = false,
});
}
日程数据模型包含了标题、描述、开始结束时间、颜色标识等字段。isAllDay字段用于标识全天事件,全天事件在日历上的显示方式与普通事件不同。Color字段允许用户为不同类型的日程设置不同颜色,便于视觉区分。
日历组件的基础结构:
class CalendarWidget extends StatefulWidget {
final List<ScheduleEvent> events;
final Function(DateTime) onDateSelected;
final Function(ScheduleEvent) onEventTap;
const CalendarWidget({
Key? key,
required this.events,
required this.onDateSelected,
required this.onEventTap,
}) : super(key: key);
State<CalendarWidget> createState() => _CalendarWidgetState();
}
日历组件接收日程事件列表和两个回调函数,onDateSelected在用户选择日期时触发,onEventTap在用户点击具体日程时触发。这种设计使日历组件专注于展示和交互,具体的业务逻辑由父组件处理。
状态类中的关键变量定义:
class _CalendarWidgetState extends State<CalendarWidget> {
DateTime _currentMonth = DateTime.now();
DateTime? _selectedDate;
CalendarView _currentView = CalendarView.month;
List<ScheduleEvent> get _selectedDateEvents {
if (_selectedDate == null) return [];
return widget.events.where((e) =>
isSameDay(e.startTime, _selectedDate!)
).toList();
}
}
状态类管理当前显示的月份、选中的日期和当前视图模式。_selectedDateEvents是一个计算属性,根据选中日期过滤出当天的日程列表。使用getter而不是普通方法可以像访问属性一样使用,代码更加简洁。
月视图网格的构建:
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 7,
childAspectRatio: 1,
),
itemCount: 42,
itemBuilder: (context, index) {
final date = _getDateForIndex(index);
final hasEvents = _hasEventsOnDate(date);
return _buildDayCell(date, hasEvents);
},
)
月视图使用GridView构建7列的网格,每行代表一周。itemCount设为42是因为一个月视图最多需要6行(上月末尾+当月+下月开头)。childAspectRatio设为1使每个单元格为正方形,这是日历的标准布局。
日期单元格的构建方法:
Widget _buildDayCell(DateTime date, bool hasEvents) {
final isSelected = _selectedDate != null && isSameDay(date, _selectedDate!);
final isToday = isSameDay(date, DateTime.now());
return GestureDetector(
onTap: () {
setState(() => _selectedDate = date);
widget.onDateSelected(date);
},
child: Container(
decoration: BoxDecoration(
color: isSelected ? Colors.blue : null,
shape: BoxShape.circle,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'${date.day}',
style: TextStyle(
color: isSelected ? Colors.white : (isToday ? Colors.blue : null),
),
),
if (hasEvents)
Container(
width: 6,
height: 6,
decoration: BoxDecoration(
color: isSelected ? Colors.white : Colors.blue,
shape: BoxShape.circle,
),
),
],
),
),
);
}
日期单元格需要处理多种状态:是否选中、是否是今天、是否有日程。选中状态用蓝色圆形背景标识,今天用蓝色文字标识,有日程的日期在数字下方显示一个小圆点。这种视觉设计让用户能够快速获取日历信息。
OpenHarmony鸿蒙端实现
定义日程数据接口:
interface ScheduleEvent {
id: string
title: string
description: string
startTime: number
endTime: number
color: string
isAllDay: boolean
}
鸿蒙端使用interface定义日程数据结构,时间使用时间戳格式便于计算和比较。color字段存储十六进制颜色字符串,用于在日历上区分不同类型的日程。
日历组件的基础结构:
@Component
struct CalendarWidget {
@State currentMonth: Date = new Date()
@State selectedDate: Date | null = null
@Prop events: ScheduleEvent[] = []
private onDateSelect: (date: Date) => void = () => {}
}
组件使用@State管理当前月份和选中日期,@Prop接收外部传入的日程列表。Date类型用于日期操作,鸿蒙的ArkTS完全支持JavaScript的Date对象。
月份切换头部的构建:
@Builder
CalendarHeader() {
Row() {
Image($r('app.media.arrow_left'))
.width(24)
.height(24)
.onClick(() => this.previousMonth())
Text(this.formatMonth(this.currentMonth))
.fontSize(18)
.fontWeight(FontWeight.Medium)
.margin({ left: 16, right: 16 })
Image($r('app.media.arrow_right'))
.width(24)
.height(24)
.onClick(() => this.nextMonth())
}
.width('100%')
.justifyContent(FlexAlign.Center)
.padding({ top: 16, bottom: 16 })
}
日历头部包含左右箭头和当前月份显示,点击箭头可以切换月份。$r语法用于引用资源文件中的图片,这是鸿蒙推荐的资源引用方式。justifyContent设置为Center使内容居中显示。
星期标题行的构建:
@Builder
WeekdayHeader() {
Row() {
ForEach(['日', '一', '二', '三', '四', '五', '六'], (day: string) => {
Text(day)
.width('14.28%')
.textAlign(TextAlign.Center)
.fontSize(14)
.fontColor('#999999')
})
}
.width('100%')
}
星期标题行使用ForEach循环渲染七个星期文字,每个占据14.28%的宽度(100%/7)。这种百分比布局方式可以自适应不同屏幕宽度,保证日历在各种设备上都能正确显示。
日期网格的构建:
@Builder
DateGrid() {
Grid() {
ForEach(this.generateMonthDates(), (date: Date, index: number) => {
GridItem() {
this.DateCell(date)
}
})
}
.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
.rowsGap(8)
.columnsGap(0)
}
鸿蒙的Grid组件用于构建网格布局,columnsTemplate定义7列等宽布局,1fr表示等分剩余空间。rowsGap设置行间距,使日期之间有适当的视觉间隔。
日期单元格的构建:
@Builder
DateCell(date: Date) {
Column() {
Text(`${date.getDate()}`)
.fontSize(16)
.fontColor(this.isSelected(date) ? Color.White :
this.isToday(date) ? '#1890FF' : '#333333')
if (this.hasEvents(date)) {
Circle()
.width(6)
.height(6)
.fill(this.isSelected(date) ? Color.White : '#1890FF')
.margin({ top: 2 })
}
}
.width('100%')
.aspectRatio(1)
.justifyContent(FlexAlign.Center)
.backgroundColor(this.isSelected(date) ? '#1890FF' : Color.Transparent)
.borderRadius(20)
.onClick(() => {
this.selectedDate = date
this.onDateSelect(date)
})
}
日期单元格使用Column垂直排列日期数字和日程指示点。aspectRatio(1)确保单元格为正方形,borderRadius(20)在选中时创建圆形背景效果。条件渲染根据是否有日程决定是否显示指示点。
选中日期的日程列表:
@Builder
EventList() {
if (this.selectedDate !== null) {
List({ space: 8 }) {
ForEach(this.getEventsForDate(this.selectedDate), (event: ScheduleEvent) => {
ListItem() {
Row() {
Divider()
.vertical(true)
.height(40)
.strokeWidth(4)
.color(event.color)
Column() {
Text(event.title)
.fontSize(14)
.fontWeight(FontWeight.Medium)
Text(this.formatEventTime(event))
.fontSize(12)
.fontColor('#666666')
}
.alignItems(HorizontalAlign.Start)
.margin({ left: 12 })
}
.padding(12)
.backgroundColor('#F5F5F5')
.borderRadius(8)
}
})
}
.width('100%')
.margin({ top: 16 })
}
}
日程列表展示选中日期的所有日程,每个日程项左侧有一个彩色竖条用于区分类型。Divider组件设置vertical(true)变为垂直分割线,strokeWidth控制宽度,color使用日程的颜色属性。这种设计使日程列表既美观又信息丰富。
总结
本文详细介绍了Flutter和OpenHarmony平台上日程日历组件的开发方法。日历组件是OA系统中复杂度较高的组件之一,需要处理日期计算、视图切换、事件渲染等多个方面。两个平台都提供了灵活的布局组件来实现日历网格,开发者需要根据业务需求选择合适的视图模式和交互方式。一个优秀的日历组件可以显著提升用户的日程管理效率。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)