移动网络详情页面展示当前移动数据连接的详细信息,包括运营商、网络类型、信号强度,以及移动数据的开关控制和漫游设置。
请添加图片描述

功能设计

移动网络详情页面需要展示:

  • 运营商信息和网络类型(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

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐