网速测试是流量监控App中很受欢迎的功能,用户可以随时检测当前网络的实际速度。这个页面的核心是一个动态的速度仪表盘,配合测试过程的动画效果,给用户直观的反馈。
请添加图片描述

页面布局设计

网速测试页面采用居中布局,主要元素从上到下依次是:

  • 速度仪表盘:环形进度条显示当前测试进度和速度
  • 测试结果卡片:延迟、下载速度、上传速度三项数据
  • 开始按钮:触发测试的主按钮

速度仪表盘实现

percent_indicator库的环形进度条作为仪表盘:

Widget _buildSpeedometer() {
  return Obx(() => CircularPercentIndicator(
    radius: 100.r,
    lineWidth: 12.w,
    percent: controller.progress.value,
    center: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(
          controller.isTesting.value ? '${controller.downloadSpeed.value.toStringAsFixed(1)}' : '0',
          style: TextStyle(fontSize: 36.sp, fontWeight: FontWeight.bold, color: AppTheme.primaryColor),
        ),
// _buildSpeedometer使用CircularPercentIndicator构建环形仪表盘。
// radius设为100像素,lineWidth设为12像素控制环形粗细。
// percent绑定controller.progress,实现进度动画效果。

        Text('Mbps', style: TextStyle(fontSize: 14.sp, color: AppTheme.textSecondary)),
      ],
    ),
    progressColor: AppTheme.primaryColor,
    backgroundColor: Colors.grey.shade200,
    circularStrokeCap: CircularStrokeCap.round,
  ));
}

参数解析

  • radius: 100.r:仪表盘半径,100是个比较大的尺寸,作为页面的视觉中心
  • lineWidth: 12.w:进度条粗细,太细看不清,太粗显得笨重
  • percent:进度值,0到1之间,绑定controller的progress变量
  • circularStrokeCap: CircularStrokeCap.round:进度条两端是圆形,比方形更柔和

中心内容:测试中显示实时速度,未测试时显示0。速度数字用36sp的大字号,单位"Mbps"用小字号放在下面。

测试结果卡片

展示延迟、下载、上传三项测试结果:

Widget _buildResults() {
  return Container(
    margin: EdgeInsets.symmetric(horizontal: 32.w),
    padding: EdgeInsets.all(20.w),
    decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(16.r)),
    child: Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: [
        _buildResultItem('延迟', '${controller.ping.value}', 'ms'),
        _buildResultItem('下载', '${controller.downloadSpeed.value.toStringAsFixed(1)}', 'Mbps'),
        _buildResultItem('上传', '${controller.uploadSpeed.value.toStringAsFixed(1)}', 'Mbps'),
// _buildResults构建测试结果卡片,水平外边距32像素。
// 内边距20像素,白色背景配合16像素圆角。
// Row使用spaceAround均匀分布三个结果项。

      ],
    ),
  );
}

Widget _buildResultItem(String label, String value, String unit) {
  return Column(
    children: [
      Text(label, style: TextStyle(fontSize: 12.sp, color: AppTheme.textSecondary)),
      SizedBox(height: 4.h),
      Obx(() => Text(value, style: TextStyle(fontSize: 20.sp, fontWeight: FontWeight.bold))),
      Text(unit, style: TextStyle(fontSize: 10.sp, color: AppTheme.textSecondary)),
    ],
  );
// _buildResultItem是复用组件,接收标签、数值和单位参数。
// Column垂直排列标签、数值和单位三行文字。
// 数值用Obx包裹实现实时更新,20sp粗体突出显示。

}

三项数据等间距排列,每项包含标签、数值、单位三行。数值用Obx包裹实现实时更新。

开始测试按钮

按钮在测试中和空闲时显示不同的文字:

Widget _buildStartButton() {
  return Obx(() => ElevatedButton(
    onPressed: controller.isTesting.value ? null : controller.startTest,
    style: ElevatedButton.styleFrom(
      backgroundColor: AppTheme.primaryColor,
      padding: EdgeInsets.symmetric(horizontal: 60.w, vertical: 16.h),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.r)),
    ),
    child: Text(
      controller.isTesting.value ? controller.testPhase.value : '开始测速',
      style: TextStyle(fontSize: 16.sp, color: Colors.white),
// _buildStartButton构建开始测试按钮,用Obx包裹响应状态变化。
// 测试中时onPressed设为null禁用按钮,防止重复点击。
// 按钮样式使用主题色背景,30像素圆角形成胶囊形状。

    ),
  ));
}

测试中禁用按钮onPressed设为null会自动禁用按钮,防止用户重复点击。

动态文字:测试中显示当前阶段(“测试延迟…”、"测试下载速度…"等),让用户知道测试进行到哪一步了。

按钮样式:圆角30的胶囊形按钮,横向padding较大让按钮看起来更宽。

Controller层的测试逻辑

测试过程分为三个阶段:延迟测试、下载测试、上传测试:

class SpeedTestController extends GetxController {
  final isTesting = false.obs;
  final downloadSpeed = 0.0.obs;
  final uploadSpeed = 0.0.obs;
  final ping = 0.obs;
  final progress = 0.0.obs;
  final testPhase = ''.obs;

  void startTest() async {
    isTesting.value = true;
    progress.value = 0;
    downloadSpeed.value = 0;
// SpeedTestController定义测试相关的所有响应式状态变量。
// isTesting控制测试状态,progress控制进度条进度。
// downloadSpeed、uploadSpeed、ping分别存储三项测试结果。

    uploadSpeed.value = 0;
    ping.value = 0;

    // 阶段1:测试延迟
    testPhase.value = '测试延迟...';
    await Future.delayed(const Duration(seconds: 1));
    ping.value = 25;
    progress.value = 0.2;

    // 阶段2:测试下载速度
    testPhase.value = '测试下载速度...';
    for (int i = 0; i < 10; i++) {
      await Future.delayed(const Duration(milliseconds: 200));
// startTest方法启动测试,首先重置所有状态变量。
// 阶段1测试延迟,模拟1秒后得到25ms的延迟结果。
// 阶段2测试下载速度,循环10次模拟速度逐渐增加的效果。

      downloadSpeed.value = (i + 1) * 12.5;
      progress.value = 0.2 + (i + 1) * 0.04;
    }

    // 阶段3:测试上传速度
    testPhase.value = '测试上传速度...';
    for (int i = 0; i < 10; i++) {
      await Future.delayed(const Duration(milliseconds: 200));
      uploadSpeed.value = (i + 1) * 4.5;
      progress.value = 0.6 + (i + 1) * 0.04;
    }

    testPhase.value = '测试完成';
    isTesting.value = false;
// 每次循环更新downloadSpeed和progress,让仪表盘有动画效果。
// 阶段3测试上传速度,逻辑与下载测试类似。
// 测试完成后设置testPhase为"测试完成",isTesting设为false。

  }
}

模拟测试过程:用Future.delayed模拟网络请求的耗时,循环更新速度值让仪表盘有动画效果。

进度分配:延迟测试占20%,下载测试占40%,上传测试占40%。每个阶段内部再细分进度。

实际项目中的实现:真正的网速测试需要向测速服务器发送请求,计算数据传输的实际速度。可以使用专门的测速API,或者自己搭建测速服务器。

页面整体结构


Widget build(BuildContext context) {
  return Scaffold(
    backgroundColor: AppTheme.backgroundColor,
    appBar: AppBar(title: const Text('网络测速')),
    body: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          _buildSpeedometer(),
          SizedBox(height: 40.h),
          _buildResults(),
// build方法返回Scaffold,设置背景色和AppBar标题。
// body使用Center让内容居中显示。
// Column使用mainAxisAlignment.center垂直居中排列子组件。

          SizedBox(height: 40.h),
          _buildStartButton(),
        ],
      ),
    ),
  );
}

整个内容居中显示,用CenterMainAxisAlignment.center实现。三个区块之间用40像素的间距分隔。

可以优化的地方

历史记录:保存每次测试的结果,让用户可以查看历史测速记录,对比不同时间、不同网络的速度。

测速服务器选择:提供多个测速服务器让用户选择,不同服务器的测试结果可能有差异。

网络类型显示:在测试前显示当前连接的是WiFi还是移动数据,以及信号强度。

分享功能:测试完成后可以生成一张测速结果图片,方便用户分享到社交媒体。

网速测试功能虽然不复杂,但动画效果和用户反馈做好了,能给用户很好的体验。


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

Logo

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

更多推荐