news 2026/5/8 10:22:51

Flutter for OpenHarmony移动数据使用监管助手App实战 - 流量日历实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flutter for OpenHarmony移动数据使用监管助手App实战 - 流量日历实现

流量日历是一个非常实用的功能,它以日历的形式展示每天的流量使用情况。用户可以直观地看到哪些天用得多、哪些天用得少,从而发现自己的流量使用规律。这个页面使用table_calendar库实现日历功能,配合GetX进行状态管理。

功能入口

流量日历可以从统计页面进入:

ListTile(leading:Icon(Icons.calendar_month,color:AppTheme.primaryColor),title:constText('流量日历'),subtitle:constText('查看每日流量使用'),trailing:constIcon(Icons.chevron_right),onTap:()=>Get.toNamed(Routes.DATA_CALENDAR),)

点击后跳转到/data-calendar路由,进入日历页面。

页面整体结构

流量日历页面采用Column布局,从上到下分为三个部分:

classDataCalendarViewextendsGetView<DataCalendarController>{constDataCalendarView({super.key});@overrideWidgetbuild(BuildContextcontext){returnScaffold(backgroundColor:AppTheme.backgroundColor,appBar:AppBar(title:constText('流量日历')),body:Column(children:[_buildCalendar(),SizedBox(height:16.h),_buildSelectedDayInfo(),],),);}}

页面结构说明:

  • AppBar:标准导航栏,显示"流量日历"标题
  • 日历组件:占据页面主要区域,可以切换月份、点击选择日期
  • 选中日期信息卡片:展示选中日期的流量详情

使用GetView<DataCalendarController>可以自动获取Controller实例,无需手动调用Get.find()

日历组件实现

日历是这个页面的核心组件,使用table_calendar库实现:

Widget_buildCalendar(){returnContainer(margin:EdgeInsets.all(16.w),decoration:BoxDecoration(color:Colors.white,borderRadius:BorderRadius.circular(16.r),),child:Obx(()=>TableCalendar(firstDay:DateTime.utc(2020,1,1),lastDay:DateTime.utc(2030,12,31),focusedDay:controller.focusedDate.value,selectedDayPredicate:(day)=>isSameDay(controller.selectedDate.value,day),onDaySelected:controller.onDaySelected,calendarStyle:CalendarStyle(selectedDecoration:constBoxDecoration(color:AppTheme.primaryColor,shape:BoxShape.circle,),todayDecoration:BoxDecoration(color:AppTheme.primaryColor.withOpacity(0.3),shape:BoxShape.circle,),),headerStyle:HeaderStyle(formatButtonVisible:false,titleCentered:true,titleTextStyle:TextStyle(fontSize:16.sp,fontWeight:FontWeight.w600,),),)),);}

TableCalendar核心参数解析

  • firstDaylastDay:定义日历可选范围,这里设置从2020年到2030年,覆盖足够长的时间跨度
  • focusedDay:当前聚焦的日期,决定日历显示哪个月份
  • selectedDayPredicate:判断某天是否被选中的回调函数,返回true则该日期显示选中状态
  • onDaySelected:用户点击日期时的回调,接收选中日期和聚焦日期两个参数

CalendarStyle样式定制

  • selectedDecoration:选中日期的装饰,使用主题色圆形背景
  • todayDecoration:今天的装饰,使用半透明主题色背景,与选中状态区分

HeaderStyle头部样式

  • formatButtonVisible: false:隐藏格式切换按钮,不需要周视图/月视图切换
  • titleCentered: true:月份标题居中显示
  • titleTextStyle:自定义标题字体大小和粗细

整个日历组件包裹在白色圆角容器中,与页面背景形成层次感。使用Obx包裹确保日期变化时UI自动更新。

选中日期信息卡片

当用户选中某一天后,下方卡片会显示该日期的详细流量信息:

Widget_buildSelectedDayInfo(){returnContainer(margin:EdgeInsets.symmetric(horizontal:16.w),padding:EdgeInsets.all(20.w),decoration:BoxDecoration(color:Colors.white,borderRadius:BorderRadius.circular(16.r),),child:Obx((){finalusage=controller.getUsageForDate(controller.selectedDate.value);returnColumn(children:[Text(DateFormat('yyyy年MM月dd日').format(controller.selectedDate.value),style:TextStyle(fontSize:16.sp,fontWeight:FontWeight.w600,),),SizedBox(height:12.h),Text(controller.formatBytes(usage),style:TextStyle(fontSize:32.sp,fontWeight:FontWeight.bold,color:AppTheme.primaryColor,),),SizedBox(height:4.h),Text('当日流量使用',style:TextStyle(fontSize:12.sp,color:AppTheme.textSecondary,),),],);}),);}

卡片内容说明:

  • 日期显示:使用intl包的DateFormat将日期格式化为"2024年01月15日"这样的中文格式
  • 流量数值:大号字体突出显示,使用主题色增强视觉效果
  • 说明文字:小号灰色字体,说明数值含义

Obx包裹整个Column,当selectedDate变化时,会自动调用getUsageForDate获取新日期的流量数据并更新显示。

Controller层完整实现

Controller负责管理日历的状态和数据:

import'package:get/get.dart';classDataCalendarControllerextendsGetxController{finalselectedDate=DateTime.now().obs;finalfocusedDate=DateTime.now().obs;finaldailyUsageMap=<DateTime,int>{}.obs;@overridevoidonInit(){super.onInit();loadCalendarData();}voidloadCalendarData(){finalnow=DateTime.now();for(int i=0;i<30;i++){finaldate=DateTime(now.year,now.month,now.day-i);dailyUsageMap[date]=(500+(i%10)*100)*1024*1024;}}voidonDaySelected(DateTimeselected,DateTimefocused){selectedDate.value=selected;focusedDate.value=focused;}intgetUsageForDate(DateTimedate){finalkey=DateTime(date.year,date.month,date.day);returndailyUsageMap[key]??0;}StringformatBytes(int bytes){if(bytes<1024)return'$bytesB';if(bytes<1024*1024)return'${(bytes/1024).toStringAsFixed(1)}KB';if(bytes<1024*1024*1024){return'${(bytes/(1024*1024)).toStringAsFixed(2)}MB';}return'${(bytes/(1024*1024*1024)).toStringAsFixed(2)}GB';}}

状态变量说明

  • selectedDate:当前选中的日期,初始值为今天
  • focusedDate:日历聚焦的日期,决定显示哪个月
  • dailyUsageMap:存储每天流量数据的Map,key是日期,value是字节数

loadCalendarData方法

这个方法在Controller初始化时调用,加载最近30天的流量数据。实际项目中应该从本地数据库或服务器获取真实数据,这里用模拟数据演示。

注意创建日期时只保留年月日:DateTime(now.year, now.month, now.day - i),这样可以确保Map的key不包含时分秒,方便后续查询。

onDaySelected方法

用户点击日期时调用,同时更新选中日期和聚焦日期。table_calendar库要求同时维护这两个状态,focusedDay用于控制日历显示哪个月。

getUsageForDate方法

根据日期查询流量数据。这里有个关键点:传入的日期可能包含时分秒信息,需要先转换成只有年月日的DateTime对象,才能正确匹配Map中的key。

formatBytes方法

将字节数转换为人类可读的格式。根据数值大小自动选择合适的单位(B、KB、MB、GB),并保留适当的小数位数。

路由配置

在路由表中注册流量日历页面:

GetPage(name:Routes.DATA_CALENDAR,page:()=>constDataCalendarView(),binding:DataCalendarBinding(),)

对应的Binding类负责注入Controller:

classDataCalendarBindingextendsBindings{@overridevoiddependencies(){Get.lazyPut<DataCalendarController>(()=>DataCalendarController());}}

使用lazyPut延迟创建Controller,只有在页面真正需要时才会实例化,节省内存。

日历标记功能扩展

如果想在日历上标记有数据的日期,可以使用calendarBuilders参数自定义日期单元格:

TableCalendar(// ... 其他参数calendarBuilders:CalendarBuilders(markerBuilder:(context,date,events){finalusage=controller.getUsageForDate(date);if(usage>0){returnPositioned(bottom:1,child:Container(width:6.w,height:6.w,decoration:BoxDecoration(color:_getUsageColor(usage),shape:BoxShape.circle,),),);}returnnull;},),)

markerBuilder可以在日期下方添加小圆点标记,根据流量大小显示不同颜色,让用户一眼就能看出哪些天流量用得多。

颜色判断逻辑可以这样实现:

Color_getUsageColor(int bytes){finalmb=bytes/(1024*1024);if(mb>1000)returnColors.red;if(mb>500)returnColors.orange;returnColors.green;}

流量超过1GB显示红色,500MB到1GB显示橙色,500MB以下显示绿色。

月份切换回调

如果需要在用户切换月份时加载对应月份的数据,可以使用onPageChanged回调:

TableCalendar(// ... 其他参数onPageChanged:(focusedDay){controller.focusedDate.value=focusedDay;controller.loadMonthData(focusedDay);},)

Controller中添加按月加载数据的方法:

voidloadMonthData(DateTimemonth){finalfirstDay=DateTime(month.year,month.month,1);finallastDay=DateTime(month.year,month.month+1,0);// 加载该月份的流量数据// 实际项目中这里应该调用数据服务}

这样可以实现按需加载,避免一次性加载过多数据。

依赖包说明

流量日历功能需要以下依赖:

dependencies:table_calendar:^3.0.9intl:^0.18.1
  • table_calendar:功能强大的日历组件,支持多种视图和自定义样式
  • intl:国际化支持,用于日期格式化

这两个包都兼容OpenHarmony平台,可以正常使用。

小结

流量日历通过日历视图让用户直观地查看历史流量数据,主要技术点包括:

  • 使用table_calendar库实现日历功能
  • 通过CalendarStyleHeaderStyle自定义日历外观
  • 使用Map存储日期与流量的映射关系
  • 日期比较时注意去除时分秒信息
  • 可以通过calendarBuilders添加流量标记

这个功能帮助用户发现自己的流量使用规律,比如周末是否用得更多、月初月末的使用差异等。


欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/3 13:15:47

MediaPipe Hands彩虹骨骼版:手部追踪代码实例详解

MediaPipe Hands彩虹骨骼版&#xff1a;手部追踪代码实例详解 1. 引言&#xff1a;AI手势识别与交互的现实落地 随着人机交互技术的不断演进&#xff0c;手势识别正逐步从科幻场景走向日常应用。无论是智能驾驶中的非接触控制、AR/VR中的自然交互&#xff0c;还是远程会议中的…

作者头像 李华
网站建设 2026/4/24 2:06:23

Qwen2.5降本实战案例:1GB轻量模型如何实现零GPU高效运行

Qwen2.5降本实战案例&#xff1a;1GB轻量模型如何实现零GPU高效运行 1. 背景与挑战&#xff1a;大模型落地边缘场景的现实困境 随着大语言模型&#xff08;LLM&#xff09;在各类应用中广泛渗透&#xff0c;企业对AI能力的需求日益增长。然而&#xff0c;主流大模型通常依赖高…

作者头像 李华
网站建设 2026/5/7 4:16:18

B站视频下载工具实用操作方案与资源获取指南

B站视频下载工具实用操作方案与资源获取指南 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader &#x1f633; 项目地址: https://gitcode.com/gh_mirrors/bi/BilibiliDown …

作者头像 李华
网站建设 2026/5/1 10:50:27

NewBie-image-Exp0.1实战案例:创建动漫风格滤镜应用

NewBie-image-Exp0.1实战案例&#xff1a;创建动漫风格滤镜应用 1. 引言 随着生成式AI技术的快速发展&#xff0c;基于扩散模型的图像生成在动漫创作领域展现出巨大潜力。然而&#xff0c;复杂的环境配置、依赖管理以及源码兼容性问题常常成为开发者快速验证创意的障碍。NewB…

作者头像 李华
网站建设 2026/4/24 9:18:35

Figma转代码终极秘籍:快速上手高效设计开发协作工具

Figma转代码终极秘籍&#xff1a;快速上手高效设计开发协作工具 【免费下载链接】figma-html Builder.io for Figma: AI generation, export to code, import from web 项目地址: https://gitcode.com/gh_mirrors/fi/figma-html 还在为Figma设计稿到代码的转换而烦恼吗&…

作者头像 李华
网站建设 2026/5/8 0:03:20

foo2zjs:Linux系统下的终极打印机驱动解决方案

foo2zjs&#xff1a;Linux系统下的终极打印机驱动解决方案 【免费下载链接】foo2zjs A linux printer driver for QPDL protocol - copy of http://foo2zjs.rkkda.com/ 项目地址: https://gitcode.com/gh_mirrors/fo/foo2zjs 如果你正在Linux系统上为打印机驱动问题而烦…

作者头像 李华