news 2026/6/26 20:36:04

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

作者头像

张小明

前端开发工程师

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

流量限额功能让用户可以设置每日流量上限,当使用量接近或超过限额时收到提醒。这个功能对于流量套餐有限的用户特别有用,可以有效避免超额使用导致的额外费用。通过合理设置限额,用户可以更好地规划每天的流量使用,确保月底不会出现流量不足的尴尬情况。

功能设计

流量限额页面需要实现以下核心功能:

  • 全局每日流量限额设置,控制整体的流量消耗上限
  • 单个应用的流量限额设置,针对高流量应用进行精细化管理
  • 限额开关和阈值调整,用户可以灵活控制限额策略
  • 当前使用量和剩余额度显示,让用户实时了解流量消耗情况

页面整体结构

classUsageLimitViewextendsGetView<UsageLimitController>{constUsageLimitView({super.key});@overrideWidgetbuild(BuildContextcontext){returnScaffold(backgroundColor:AppTheme.backgroundColor,appBar:AppBar(

UsageLimitView继承GetView,通过controller属性访问控制器。Scaffold提供页面基础结构。
backgroundColor设置统一的背景色,AppBar是顶部导航栏。

title:constText('流量限额'),actions:[IconButton(icon:Icon(Icons.history),onPressed:()=>_showLimitHistory(),),],),

title设置页面标题。actions添加历史记录按钮,点击显示限额触发的历史记录。
用户可以回顾哪些时候超过了限额,帮助调整限额设置。

body:SingleChildScrollView(padding:EdgeInsets.all(16.w),child:Column(children:[_buildDailyLimitCard(),SizedBox(height:16.h),_buildCurrentUsage(),

body使用SingleChildScrollView支持滚动,padding设置16.w内边距。
Column垂直排列三个区域:每日限额卡片、当前使用情况、应用限额列表。

SizedBox(height:16.h),_buildAppLimitsSection(),],),),);}}

SizedBox添加16.h的垂直间距分隔各区域。_buildAppLimitsSection构建应用限额列表。
页面从上到下:全局设置、当前状态、细分控制,符合从整体到局部的认知习惯。

每日限额卡片

Widget_buildDailyLimitCard(){returnContainer(padding:EdgeInsets.all(20.w),decoration:BoxDecoration(color:Colors.white,borderRadius:BorderRadius.circular(16.r),boxShadow:[

Container创建卡片容器,内边距20.w,白色背景,圆角16.r。
boxShadow添加阴影效果,让卡片有悬浮感。

BoxShadow(color:Colors.black.withOpacity(0.03),blurRadius:10.r,offset:Offset(0,4.h),),],),child:Column(crossAxisAlignment:CrossAxisAlignment.start,

阴影使用3%透明度黑色,模糊半径10,向下偏移4像素,形成自然的投影。
Column垂直排列内容,crossAxisAlignment设置左对齐。

children:[Row(mainAxisAlignment:MainAxisAlignment.spaceBetween,children:[Text('每日流量限额',style:TextStyle(fontSize:18.sp,fontWeight:FontWeight.bold)),Obx(()=>Switch(

Row横向排列标题和开关,spaceBetween让它们分居两端。
标题18sp粗体,是卡片的主标题。Obx包裹Switch响应状态变化。

value:controller.dailyLimitEnabled.value,onChanged:(v)=>controller.dailyLimitEnabled.value=v,activeColor:AppTheme.primaryColor,)),],),SizedBox(height:8.h),Text('开启后,当日流量超过限额时会收到提醒',style:TextStyle(fontSize:13.sp,color:AppTheme.textSecondary)),

Switch绑定dailyLimitEnabled状态,onChanged更新状态值。activeColor设置开启时的颜色。
说明文字13sp次要颜色,解释功能作用。

SizedBox(height:20.h),_buildLimitSlider(),SizedBox(height:16.h),_buildQuickOptions(),],),);}

SizedBox添加间距。_buildLimitSlider构建限额滑块,_buildQuickOptions构建快捷选项按钮。
卡片结构:标题+开关、说明文字、滑块、快捷选项。

限额滑块

Widget_buildLimitSlider(){returnObx((){finalisEnabled=controller.dailyLimitEnabled.value;returnColumn(children:[Row(mainAxisAlignment:MainAxisAlignment.center,

Obx包裹整个滑块区域,响应dailyLimitEnabled和dailyLimit的变化。
isEnabled缓存启用状态,避免重复访问。Column垂直排列数字显示和滑块。

children:[Text('${controller.dailyLimit.value.toStringAsFixed(1)}',style:TextStyle(fontSize:48.sp,fontWeight:FontWeight.bold,color:isEnabled?AppTheme.primaryColor:Colors.grey),),SizedBox(width:8.w),

限额数值用48sp超大字号显示,是视觉焦点。toStringAsFixed(1)保留一位小数。
颜色根据启用状态变化:启用时蓝色,禁用时灰色。SizedBox添加间距。

Text('GB/天',style:TextStyle(fontSize:16.sp,color:isEnabled?AppTheme.primaryColor:Colors.grey)),],),SizedBox(height:16.h),Slider(value:controller.dailyLimit.value,

单位"GB/天"16sp,颜色同样根据状态变化。SizedBox添加16.h间距。
Slider是Flutter的滑块组件,value绑定dailyLimit值。

min:0.5,max:5.0,divisions:9,onChanged:isEnabled?(v)=>controller.dailyLimit.value=v:null,),],);});}

min和max设置滑块范围0.5-5GB,divisions分成9档,每档0.5GB。
onChanged在启用时更新值,禁用时传null使滑块不可操作。

快捷选项

Widget_buildQuickOptions(){finaloptions=[0.5,1.0,2.0,3.0];returnRow(mainAxisAlignment:MainAxisAlignment.spaceEvenly,children:options.map((value){returnObx(()=>GestureDetector(

options定义四个常用限额值。Row横向排列,spaceEvenly均匀分布。
map遍历生成按钮,Obx响应状态变化,GestureDetector处理点击。

onTap:controller.dailyLimitEnabled.value?()=>controller.dailyLimit.value=value:null,child:Container(padding:EdgeInsets.symmetric(horizontal:16.w,vertical:8.h),decoration:BoxDecoration(

onTap在启用时设置限额值,禁用时传null不响应点击。
Container创建按钮容器,水平内边距16.w,垂直内边距8.h。

color:controller.dailyLimit.value==value?AppTheme.primaryColor:Colors.grey.shade100,borderRadius:BorderRadius.circular(20.r),),child:Text('${value.toStringAsFixed(1)}GB',style:TextStyle(fontSize:13.sp,fontWeight:FontWeight.w500,

背景色根据是否选中变化:选中时主色调,未选中时浅灰色。圆角20.r形成药丸形状。
文字显示限额值,13sp字号,中等粗细。

color:controller.dailyLimit.value==value?Colors.white:AppTheme.textSecondary)),),));}).toList(),);}

文字颜色:选中时白色,未选中时次要颜色。toList()将map结果转为列表。
快捷选项让用户一键设置常用值,比拖动滑块更快捷。

当前使用情况

Widget_buildCurrentUsage(){returnContainer(padding:EdgeInsets.all(16.w),decoration:BoxDecoration(gradient:LinearGradient(colors:[AppTheme.primaryColor,AppTheme.primaryColor.withOpacity(0.8)]),borderRadius:BorderRadius.circular(16.r),),

Container使用渐变背景,从主色调到80%透明度,形成从左到右变浅的效果。
圆角16.r,内边距16.w。渐变背景让这个卡片更突出。

child:Obx((){finalused=controller.todayUsed.value;finallimit=controller.dailyLimit.value;finalpercentage=controller.dailyLimitEnabled.value?(used/limit*100).clamp(0,100):0.0;returnColumn(

Obx响应数据变化。计算使用百分比,clamp限制在0-100范围内。
如果限额未启用,百分比显示为0。Column垂直排列内容。

children:[Row(mainAxisAlignment:MainAxisAlignment.spaceBetween,children:[Text('今日已使用',style:TextStyle(fontSize:14.sp,color:Colors.white70)),Text('${percentage.toStringAsFixed(1)}%',style:TextStyle(fontSize:14.sp,fontWeight:FontWeight.bold,color:Colors.white)),],),

Row显示标签和百分比,spaceBetween分居两端。标签用70%白色,百分比用纯白粗体。
在深色背景上,白色文字清晰可见。

SizedBox(height:12.h),LinearProgressIndicator(value:percentage/100,backgroundColor:Colors.white.withOpacity(0.3),valueColor:AlwaysStoppedAnimation(percentage>=90?Colors.red:Colors.white),),

SizedBox添加间距。LinearProgressIndicator显示进度条,value需要0-1的值。
背景色30%白色,进度色根据百分比变化:超过90%显示红色警告,否则白色。

SizedBox(height:12.h),Row(mainAxisAlignment:MainAxisAlignment.spaceBetween,children:[Text('${used.toStringAsFixed(2)}GB',style:TextStyle(fontSize:20.sp,fontWeight:FontWeight.bold,color:Colors.white)),Text('剩余${(limit-used).clamp(0,limit).toStringAsFixed(2)}GB',style:TextStyle(fontSize:14.sp,color:Colors.white70)),],),],);}),);}

底部Row显示已使用量和剩余量。已使用20sp大字号粗体白色,剩余14sp次要白色。
clamp确保剩余量不会显示负数。双数据展示让用户同时了解两个维度。

应用限额区域

Widget_buildAppLimitsSection(){returnContainer(decoration:BoxDecoration(color:Colors.white,borderRadius:BorderRadius.circular(16.r)),child:Column(children:[Padding(padding:EdgeInsets.all(16.w),

Container创建白色圆角卡片。Column垂直排列标题区域和列表。
Padding为标题区域添加16.w内边距。

child:Row(mainAxisAlignment:MainAxisAlignment.spaceBetween,children:[Text('应用流量限额',style:TextStyle(fontSize:16.sp,fontWeight:FontWeight.w600)),TextButton(onPressed:()=>_showAddAppDialog(),child:Text('添加应用')),],),),

Row横向排列标题和添加按钮。标题16sp半粗体,TextButton是文字按钮。
点击"添加应用"弹出对话框选择要设置限额的应用。

Divider(height:1),_buildAppLimitsList(),],),);}

Divider添加1像素高的分隔线。_buildAppLimitsList构建应用限额列表。
分隔线将标题区域和列表区域视觉上分开。

Controller实现

classUsageLimitControllerextendsGetxController{finaldailyLimitEnabled=false.obs;finaldailyLimit=1.0.obs;finaltodayUsed=0.0.obs;finalappLimits=<Map<String,dynamic>>[].obs;finalavailableApps=['微信','QQ','抖音','哔哩哔哩','淘宝','支付宝'];

声明响应式变量:dailyLimitEnabled是开关状态,dailyLimit是限额值,todayUsed是今日使用量。
appLimits是应用限额列表,availableApps是可选择的应用列表。.obs转为响应式。

voidaddAppLimit(Stringname,int limit){appLimits.add({'name':name,'limit':limit,'enabled':true});saveSettings();}voidupdateAppLimit(Stringname,int limit){finalindex=appLimits.indexWhere((app)=>app['name']==name);

addAppLimit添加应用限额,创建包含name、limit、enabled的Map并添加到列表。
updateAppLimit更新应用限额,indexWhere查找应用在列表中的索引。

if(index!=-1){appLimits[index]['limit']=limit;appLimits.refresh();}}voidremoveAppLimit(Stringname){appLimits.removeWhere((app)=>app['name']==name);}}

找到后更新limit值,调用refresh()通知GetX数据变化。removeAppLimit删除指定应用的限额。
removeWhere删除满足条件的元素。每个操作后都应调用saveSettings保存到本地。

写在最后

流量限额功能帮助用户控制每日流量消耗,避免超额使用。通过直观的滑块设置、实时的使用量显示、灵活的应用限额管理,用户可以精细化控制自己的流量使用。


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

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

告别低效编程:OpenCode LSP智能助手让终端开发焕然一新

告别低效编程&#xff1a;OpenCode LSP智能助手让终端开发焕然一新 【免费下载链接】opencode 一个专为终端打造的开源AI编程助手&#xff0c;模型灵活可选&#xff0c;可远程驱动。 项目地址: https://gitcode.com/GitHub_Trending/openc/opencode 你是否曾经在终端编写…

作者头像 李华
网站建设 2026/6/21 17:06:24

有效括号序列

求解代码 public boolean isValid (String s) {char[] str s.toCharArray();Stack<Character> stackData new Stack<>();for(char c:str){if(c(){stackData.push());}else if(c[){stackData.push(]);}else if(c{){stackData.push(});}else if(stackData.isEmpty(…

作者头像 李华
网站建设 2026/6/10 22:10:14

大规模部署HY-MT1.5-7B:成本控制与性能平衡

大规模部署HY-MT1.5-7B&#xff1a;成本控制与性能平衡 随着多语言交流需求的不断增长&#xff0c;高质量、低延迟的机器翻译服务已成为全球化应用的核心基础设施。在这一背景下&#xff0c;混元翻译模型&#xff08;HY-MT&#xff09;系列凭借其卓越的语言覆盖能力和翻译质量…

作者头像 李华
网站建设 2026/6/19 10:19:11

周末玩转Youtu-2B:云端GPU按小时计费,1块钱体验

周末玩转Youtu-2B&#xff1a;云端GPU按小时计费&#xff0c;1块钱体验 你是不是也和我一样&#xff0c;作为一名程序员&#xff0c;总想第一时间尝鲜最新的AI对话技术&#xff1f;但现实是&#xff1a;高端显卡动辄上万&#xff0c;本地部署环境配置复杂&#xff0c;光是装个…

作者头像 李华
网站建设 2026/6/14 5:52:55

Swift-All强化学习:云端GPU集群,支持并行采样

Swift-All强化学习&#xff1a;云端GPU集群&#xff0c;支持并行采样 你是不是也遇到过这样的问题&#xff1a;想训练一个游戏AI&#xff0c;让它学会打《星际争霸》或者《王者荣耀》&#xff0c;但本地电脑跑不动&#xff1f;一开多个环境就卡死&#xff0c;训练速度慢得像蜗…

作者头像 李华
网站建设 2026/6/24 21:55:46

RevokeMsgPatcher防撤回补丁:如何3步搞定消息防撤回?

RevokeMsgPatcher防撤回补丁&#xff1a;如何3步搞定消息防撤回&#xff1f; 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁&#xff08;我已经看到了&#xff0c;撤回也没用了&#xff09; 项目地址: https://…

作者头像 李华