Flutter for OpenHarmony移动数据使用监管助手App实战 - 移动网络详情实现
移动网络详情页面展示运营商、网络类型、信号强度等关键信息,并提供数据开关、漫游设置等功能。页面采用渐变色卡片设计,分为头部信息、流量统计、设置开关和网络模式四个区域。头部展示信号强度图标(带百分比)、运营商名称和网络状态;中间部分显示今日数据用量;底部提供移动数据开关、漫游设置和网络模式选择。整个界面采用响应式设计,信号强度和运营商信息实时更新,通过Obx实现数据绑定。页面布局采用Material
移动网络详情页面展示当前移动数据连接的详细信息,包括运营商、网络类型、信号强度,以及移动数据的开关控制和漫游设置。
功能设计
移动网络详情页面需要展示:
- 运营商信息和网络类型(4G/5G)
- 信号强度
- 今日移动数据使用量
- 移动数据开关
- 数据漫游开关
- 网络模式选择
页面整体结构
首先定义移动网络详情页面的基本框架:
class MobileDetailView extends GetView<MobileDetailController> {
const MobileDetailView({super.key});
Widget build(BuildContext context) {
继承GetView自动注入MobileDetailController。
const构造函数优化widget重建性能。
build方法返回页面的完整UI结构。
return Scaffold(
backgroundColor: AppTheme.backgroundColor,
appBar: AppBar(
title: const Text('移动网络'),
actions: [
IconButton(
Scaffold提供Material Design页面框架。
统一背景色保持视觉一致性。
AppBar设置页面标题为"移动网络"。
icon: Icon(Icons.settings),
onPressed: () => _openSystemSettings(),
),
],
),
body: SingleChildScrollView(
settings按钮跳转到系统移动网络设置。
方便用户进行更多高级设置。
SingleChildScrollView让内容可滚动。
padding: EdgeInsets.all(16.w),
child: Column(
children: [
_buildHeader(),
SizedBox(height: 16.h),
统一的内边距让内容不贴边。
Column垂直排列四个卡片区域。
16.h的间距让各区域视觉分隔清晰。
_buildUsageCard(),
SizedBox(height: 16.h),
_buildSettingsCard(),
SizedBox(height: 16.h),
_buildNetworkModeCard(),
],
),
),
);
}
}
四个区域:头部信息、流量统计、设置开关、网络模式。
每个区域封装成独立方法便于维护。
闭合所有括号完成页面结构。
网络信息头部
头部展示运营商和信号强度等核心信息:
Widget _buildHeader() {
return Container(
padding: EdgeInsets.all(24.w),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
Container作为头部卡片的容器。
24.w的内边距让内容更宽松。
LinearGradient创建渐变背景。
colors: [AppTheme.mobileColor, AppTheme.mobileColor.withOpacity(0.7)],
),
borderRadius: BorderRadius.circular(20.r),
boxShadow: [
BoxShadow(
color: AppTheme.mobileColor.withOpacity(0.3),
从移动网络主色到其0.7透明度版本渐变。
20.r大圆角让卡片更圆润。
阴影颜色与卡片颜色一致。
blurRadius: 15.r,
offset: Offset(0, 8.h),
),
],
),
child: Column(
children: [
_buildSignalIcon(),
较大的模糊半径让阴影更柔和。
阴影向下偏移8.h模拟光照效果。
Column垂直排列头部内容。
SizedBox(height: 16.h),
_buildCarrierInfo(),
SizedBox(height: 8.h),
_buildNetworkType(),
SizedBox(height: 20.h),
_buildTodayUsage(),
],
),
);
}
信号图标、运营商、网络类型、今日使用量依次排列。
不同的间距让内容层次分明。
_buildTodayUsage显示今日流量使用。
信号图标组件
显示信号强度的图标和百分比:
Widget _buildSignalIcon() {
return Obx(() {
final strength = controller.signalStrength.value;
return Container(
width: 80.w,
height: 80.w,
Obx监听signalStrength实现响应式更新。
80.w的尺寸让图标足够醒目。
Container作为图标的容器。
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
shape: BoxShape.circle,
),
child: Stack(
alignment: Alignment.center,
半透明白色背景与渐变卡片协调。
BoxShape.circle创建圆形容器。
Stack叠加图标和百分比徽章。
children: [
Icon(Icons.signal_cellular_alt, size: 48.sp, color: Colors.white),
Positioned(
bottom: 8.h,
child: Container(
信号图标居中显示。
Positioned定位百分比徽章在底部。
bottom: 8.h让徽章稍微上移。
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.r),
),
白色背景让徽章突出显示。
小内边距让徽章紧凑。
10.r圆角让徽章更圆润。
child: Text(
'$strength%',
style: TextStyle(
fontSize: 10.sp,
fontWeight: FontWeight.bold,
color: AppTheme.mobileColor,
),
),
),
),
],
),
);
});
}
显示信号强度百分比。
10.sp小字号适合徽章。
移动网络主色让文字与卡片协调。
运营商和网络类型
显示运营商名称和网络类型:
Widget _buildCarrierInfo() {
return Obx(() => Text(
controller.carrier.value,
style: TextStyle(
fontSize: 24.sp,
fontWeight: FontWeight.bold,
color: Colors.white,
),
));
}
Obx监听carrier变量实现响应式更新。
24.sp大字号突出显示运营商名称。
白色文字与渐变背景对比明显。
Widget _buildNetworkType() {
return Obx(() {
final type = controller.networkType.value;
final strength = controller.signalStrength.value;
String level;
Obx监听networkType和signalStrength。
根据信号强度计算等级描述。
level存储信号等级文字。
if (strength >= 80) {
level = '信号极好';
} else if (strength >= 60) {
level = '信号良好';
} else if (strength >= 40) {
level = '信号一般';
} else {
level = '信号较弱';
}
80%以上为"极好"。
60-80%为"良好"。
40-60%为"一般",40%以下为"较弱"。
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 4.h),
decoration: BoxDecoration(
Row居中排列网络类型和信号等级。
Container包裹网络类型标签。
padding让标签有适当的内边距。
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(12.r),
),
child: Text(
type,
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
半透明白色背景与卡片协调。
显示网络类型如"5G"或"4G"。
w600字重让文字稍微加粗。
SizedBox(width: 8.w),
Text(
'· $level',
style: TextStyle(fontSize: 14.sp, color: Colors.white70),
),
],
);
});
}
间距8.w让两部分不会太挤。
信号等级用白色70%透明度。
点号分隔网络类型和信号等级。
今日使用量
显示今日移动数据使用量:
Widget _buildTodayUsage() {
return Container(
padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 12.h),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.15),
borderRadius: BorderRadius.circular(12.r),
),
Container包裹今日使用量信息。
半透明白色背景与卡片协调。
12.r圆角保持视觉一致。
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.data_usage, size: 20.sp, color: Colors.white),
SizedBox(width: 8.w),
Row横向排列图标和文字。
mainAxisSize.min让容器宽度自适应。
data_usage图标表示流量使用。
Text('今日使用: ', style: TextStyle(fontSize: 14.sp, color: Colors.white70)),
Obx(() => Text(
controller.formatBytes(controller.todayUsage.value),
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.white,
),
)),
],
),
);
}
标签用白色70%透明度。
数值用18.sp大字号加粗突出。
formatBytes格式化字节数为可读字符串。
流量使用卡片
展示本周和本月的流量统计:
Widget _buildUsageCard() {
return Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.r),
),
白色背景卡片与页面灰色背景对比。
16.w内边距让内容不贴边。
16.r圆角保持视觉一致。
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'移动数据统计',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color: AppTheme.textPrimary,
),
),
Column垂直排列标题和内容。
标题用16.sp字号,w600加粗。
crossAxisAlignment让标题左对齐。
SizedBox(height: 16.h),
Row(
children: [
Expanded(child: _buildUsageItem('本周', controller.weekUsage, AppTheme.mobileColor)),
Container(width: 1, height: 50.h, color: Colors.grey.shade200),
Expanded(child: _buildUsageItem('本月', controller.monthUsage, AppTheme.primaryColor)),
],
),
Row横向排列本周和本月统计。
中间用竖线分隔。
Expanded让两边平分宽度。
SizedBox(height: 16.h),
_buildUsageProgress(),
],
),
);
}
间距16.h后显示套餐使用进度。
_buildUsageProgress显示进度条。
整体布局清晰直观。
使用量项组件
单个使用量统计项:
Widget _buildUsageItem(String label, RxInt usage, Color color) {
return Column(
children: [
Text(label, style: TextStyle(fontSize: 13.sp, color: AppTheme.textSecondary)),
SizedBox(height: 8.h),
接收标签、使用量和颜色三个参数。
Column垂直排列标签和数值。
标签用13.sp小字号,次要颜色。
Obx(() => Text(
controller.formatBytes(usage.value),
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: color,
),
)),
],
);
}
Obx监听usage实现响应式更新。
数值用18.sp大字号加粗。
颜色参数让不同项有不同颜色。
套餐使用进度
显示套餐使用进度条:
Widget _buildUsageProgress() {
return Obx(() {
final used = controller.monthUsage.value;
final total = controller.planTotal.value;
final percentage = total > 0 ? (used / total * 100).clamp(0, 100) : 0.0;
Obx监听monthUsage和planTotal。
计算使用百分比。
clamp限制在0-100范围内。
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('套餐使用进度', style: TextStyle(fontSize: 13.sp, color: AppTheme.textSecondary)),
Column垂直排列标签和进度条。
Row两端对齐标签和百分比。
标签用13.sp小字号。
Text(
'${percentage.toStringAsFixed(1)}%',
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.bold,
color: percentage >= 80 ? Colors.orange : AppTheme.primaryColor,
),
),
],
),
百分比保留一位小数。
超过80%用橙色警示。
否则用主色调显示。
SizedBox(height: 8.h),
ClipRRect(
borderRadius: BorderRadius.circular(4.r),
child: LinearProgressIndicator(
value: percentage / 100,
backgroundColor: Colors.grey.shade200,
ClipRRect给进度条添加圆角。
LinearProgressIndicator显示进度。
value是0-1的小数。
valueColor: AlwaysStoppedAnimation(
percentage >= 80 ? Colors.orange : AppTheme.mobileColor,
),
minHeight: 8.h,
),
),
],
);
});
}
进度条颜色也根据百分比变化。
minHeight设置进度条高度。
整体设计直观易懂。
设置卡片
移动数据和漫游的开关设置:
Widget _buildSettingsCard() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.r),
),
白色背景卡片。
16.r圆角保持视觉一致。
包含两个开关设置项。
child: Column(
children: [
Obx(() => SwitchListTile(
title: Text(
'移动数据',
style: TextStyle(fontSize: 15.sp, fontWeight: FontWeight.w500),
),
Column垂直排列两个设置项。
第一项:移动数据开关。
标题用15.sp字号,稍微加粗。
subtitle: Text(
controller.dataEnabled.value ? '已开启' : '已关闭',
style: TextStyle(fontSize: 13.sp, color: AppTheme.textSecondary),
),
secondary: Container(
width: 44.w,
height: 44.w,
副标题动态显示当前状态。
secondary放置左侧图标。
44.w的图标容器尺寸。
decoration: BoxDecoration(
color: controller.dataEnabled.value
? AppTheme.mobileColor.withOpacity(0.1)
: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12.r),
),
开启时用移动网络主色浅色背景。
关闭时用灰色背景。
12.r圆角让容器更圆润。
child: Icon(
Icons.signal_cellular_alt,
color: controller.dataEnabled.value ? AppTheme.mobileColor : Colors.grey,
size: 24.sp,
),
),
value: controller.dataEnabled.value,
onChanged: (v) => controller.toggleData(v),
activeColor: AppTheme.primaryColor,
)),
图标颜色也根据状态变化。
value绑定dataEnabled状态。
onChanged调用控制器方法。
Divider(height: 1, indent: 72.w),
Obx(() => SwitchListTile(
title: Text(
'数据漫游',
style: TextStyle(fontSize: 15.sp, fontWeight: FontWeight.w500),
),
分隔线与图标右边缘对齐。
第二项:数据漫游开关。
漫游可能产生额外费用。
subtitle: Text(
'在国外或其他运营商网络下使用数据',
style: TextStyle(fontSize: 13.sp, color: AppTheme.textSecondary),
),
secondary: Container(
width: 44.w,
height: 44.w,
副标题说明漫游的含义。
帮助用户理解功能用途。
图标容器样式与上一项一致。
decoration: BoxDecoration(
color: controller.roamingEnabled.value
? Colors.orange.withOpacity(0.1)
: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12.r),
),
child: Icon(
Icons.public,
color: controller.roamingEnabled.value ? Colors.orange : Colors.grey,
size: 24.sp,
),
),
漫游用橙色表示警示。
public图标表示全球/国际。
颜色根据状态变化。
value: controller.roamingEnabled.value,
onChanged: (v) => controller.toggleRoaming(v),
activeColor: AppTheme.primaryColor,
)),
],
),
);
}
绑定roamingEnabled状态。
toggleRoaming会弹出警告对话框。
闭合Column和Container。
网络模式选择
让用户选择首选的网络类型:
Widget _buildNetworkModeCard() {
return Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.r),
),
白色背景卡片。
16.w内边距让内容不贴边。
16.r圆角保持视觉一致。
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'首选网络类型',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color: AppTheme.textPrimary,
),
),
Column垂直排列标题和选项。
标题用16.sp字号,w600加粗。
crossAxisAlignment让标题左对齐。
SizedBox(height: 4.h),
Text(
'选择优先使用的网络类型',
style: TextStyle(fontSize: 13.sp, color: AppTheme.textSecondary),
),
SizedBox(height: 16.h),
_buildNetworkModeOptions(),
],
),
);
}
副标题说明功能用途。
间距16.h后显示选项列表。
_buildNetworkModeOptions构建选项。
网络模式选项
四种网络模式的单选列表:
Widget _buildNetworkModeOptions() {
final modes = [
{'name': '5G/4G/3G/2G(自动)', 'value': 0},
{'name': '4G/3G/2G', 'value': 1},
{'name': '仅3G/2G', 'value': 2},
{'name': '仅2G', 'value': 3},
];
定义四种网络模式选项。
第一个是自动模式,根据信号自动切换。
其他是手动限制网络类型。
return Column(
children: modes.map((mode) {
return Obx(() => RadioListTile<int>(
title: Text(
mode['name'] as String,
style: TextStyle(fontSize: 14.sp),
),
Column垂直排列四个选项。
map遍历modes生成RadioListTile。
Obx监听选中状态。
value: mode['value'] as int,
groupValue: controller.networkMode.value,
onChanged: (v) => controller.setNetworkMode(v!),
activeColor: AppTheme.primaryColor,
contentPadding: EdgeInsets.zero,
));
}).toList(),
);
}
value是当前选项的值。
groupValue绑定当前选中的值。
contentPadding去掉默认内边距。
Controller实现
控制器管理移动网络相关的状态:
class MobileDetailController extends GetxController {
final carrier = '中国移动'.obs;
final networkType = '5G'.obs;
final signalStrength = 75.obs;
final dataEnabled = true.obs;
final roamingEnabled = false.obs;
final networkMode = 0.obs;
定义移动网络相关的响应式变量。
carrier存储运营商名称。
networkType存储当前网络类型。
final todayUsage = 0.obs;
final weekUsage = 0.obs;
final monthUsage = 0.obs;
final planTotal = (10 * 1024 * 1024 * 1024).obs;
void onInit() {
super.onInit();
loadMobileInfo();
loadUsageStats();
}
流量统计相关的变量。
planTotal是套餐总流量,默认10GB。
onInit加载移动网络信息和流量统计。
void loadUsageStats() {
todayUsage.value = 1024 * 1024 * 206;
weekUsage.value = 1024 * 1024 * 1024 * 1;
monthUsage.value = 1024 * 1024 * 1024 * 6;
}
加载流量统计数据。
模拟数据:今日206MB,本周1GB,本月6GB。
实际项目中从系统API获取。
void toggleData(bool enabled) {
dataEnabled.value = enabled;
if (enabled) {
Get.snackbar('移动数据', '已开启移动数据');
} else {
Get.snackbar('移动数据', '已关闭移动数据');
}
}
toggleData处理移动数据开关。
更新状态后显示snackbar提示。
实际项目中需要调用系统API。
void toggleRoaming(bool enabled) {
if (enabled) {
_showRoamingWarning();
} else {
roamingEnabled.value = false;
}
}
toggleRoaming处理漫游开关。
开启时弹出警告对话框。
关闭时直接更新状态。
void _showRoamingWarning() {
Get.dialog(
AlertDialog(
title: Text('开启数据漫游'),
content: Text('数据漫游可能产生额外费用,确定要开启吗?'),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text('取消'),
),
警告对话框提醒用户漫游费用。
取消按钮关闭对话框。
用户需要确认才能开启漫游。
ElevatedButton(
onPressed: () {
roamingEnabled.value = true;
Get.back();
},
child: Text('确定'),
),
],
),
);
}
确定后开启漫游并关闭对话框。
这种设计防止用户误操作。
漫游费用可能很高。
void setNetworkMode(int mode) {
networkMode.value = mode;
Get.snackbar('网络模式', '已切换网络模式');
}
String formatBytes(int bytes) {
if (bytes < 1024) return '$bytes B';
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)} KB';
setNetworkMode更新网络模式选择。
formatBytes格式化字节数。
根据大小选择合适的单位。
if (bytes < 1024 * 1024 * 1024) return '${(bytes / (1024 * 1024)).toStringAsFixed(2)} MB';
return '${(bytes / (1024 * 1024 * 1024)).toStringAsFixed(2)} GB';
}
}
小于1GB显示MB,否则显示GB。
toStringAsFixed控制小数位数。
通用的字节格式化方法。
写在最后
移动网络详情页面让用户全面了解和控制移动数据连接。通过清晰的信息展示、便捷的开关控制、灵活的网络模式选择,帮助用户更好地管理移动数据使用。
可以继续优化的方向:
- 添加信号强度历史图表
- 支持APN设置
- 添加网络诊断功能
- 支持流量使用预警
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐
所有评论(0)