flutter_for_openharmony手语学习app实战+学习统计实现

学习统计页面通过图表和数据展示用户的学习情况,帮助用户了解学习效果。本文介绍如何实现一个学习统计页面,包括概览卡片、周学习图表、分类进度和详细数据。

页面基础结构

定义学习统计页面:

dart 复制代码
class StatisticsScreen extends StatelessWidget {
  const StatisticsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('学习统计')),
      body: SingleChildScrollView(
        padding: EdgeInsets.all(16.w),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            _buildOverviewCard(context),
            SizedBox(height: 16.h),
            _buildWeeklyChart(),
            SizedBox(height: 16.h),
            _buildCategoryProgress(),
            SizedBox(height: 16.h),
            _buildDetailStats(context),
          ],
        ),
      ),
    );
  }

使用StatelessWidget构建页面,SingleChildScrollView让内容可以滚动。Column纵向排列四个区域:概览卡片、周学习图表、分类进度和详细数据。crossAxisAlignment.start让内容左对齐,SizedBox控制区域间距。这种分区设计让统计信息层次清晰。

概览卡片

构建顶部的学习概览:

dart 复制代码
  Widget _buildOverviewCard(BuildContext context) {
    final userProvider = Provider.of<UserProvider>(context);
    final appProvider = Provider.of<AppProvider>(context);
    
    return Card(
      child: Padding(
        padding: EdgeInsets.all(20.w),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('学习概览', style: TextStyle(fontSize: 18.sp, fontWeight: FontWeight.bold)),
            SizedBox(height: 16.h),

从两个Provider获取统计数据,用Card包裹概览内容。标题用粗体显示,crossAxisAlignment.start让内容左对齐。这个区域展示最关键的三个指标,让用户快速了解学习情况。

概览数据行

显示三个关键指标:

dart 复制代码
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                _buildOverviewItem('总学习时长', '${userProvider.totalLearningTime}分钟', Icons.timer),
                _buildOverviewItem('已学词汇', '${appProvider.completedLessons.length}个', Icons.school),
                _buildOverviewItem('连续天数', '${userProvider.consecutiveDays}天', Icons.local_fire_department),
              ],
            ),
          ],
        ),
      ),
    );
  }

Row横向排列三个统计项,mainAxisAlignment.spaceAround让它们均匀分布。每个统计项包含标签、数值和图标,调用_buildOverviewItem方法构建。这种数据可视化让关键指标一目了然。

概览项构建

封装概览项的构建逻辑:

dart 复制代码
  Widget _buildOverviewItem(String label, String value, IconData icon) {
    return Column(
      children: [
        Icon(icon, color: const Color(0xFF00897B), size: 28.sp),
        SizedBox(height: 8.h),
        Text(value, style: TextStyle(fontSize: 18.sp, fontWeight: FontWeight.bold)),
        Text(label, style: TextStyle(fontSize: 12.sp, color: Colors.grey)),
      ],
    );
  }

Column纵向排列图标、数值和标签。图标用主题色,数值用大字号粗体,标签用小字号灰色。这种纵向布局让每个统计项独立成块,信息层次清晰。图标语义化,计时器代表时长,书本代表词汇,火焰代表连续。

周学习图表

构建本周学习柱状图:

dart 复制代码
  Widget _buildWeeklyChart() {
    return Card(
      child: Padding(
        padding: EdgeInsets.all(16.w),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('本周学习', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold)),
            SizedBox(height: 16.h),
            SizedBox(
              height: 200.h,
              child: BarChart(

Card包裹图表,标题用粗体显示。SizedBox设置图表高度为200.hBarChart是fl_chart库提供的柱状图组件,功能强大。这种图表可视化比纯数字更直观。

图表配置

配置柱状图的参数:

dart 复制代码
                BarChartData(
                  alignment: BarChartAlignment.spaceAround,
                  maxY: 20,
                  barTouchData: BarTouchData(enabled: false),
                  titlesData: FlTitlesData(
                    show: true,
                    bottomTitles: AxisTitles(
                      sideTitles: SideTitles(
                        showTitles: true,
                        getTitlesWidget: (value, meta) {
                          const days = ['一', '二', '三', '四', '五', '六', '日'];
                          return Text(days[value.toInt()], style: TextStyle(fontSize: 12.sp));
                        },
                      ),
                    ),

alignment设置柱子对齐方式,maxY设置Y轴最大值,barTouchData禁用触摸交互。titlesData配置坐标轴标题,底部显示星期几。getTitlesWidget自定义标题组件,将索引映射为中文星期

隐藏其他坐标轴

只显示底部坐标轴:

dart 复制代码
                    leftTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
                    topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
                    rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
                  ),
                  borderData: FlBorderData(show: false),

左、上、右三个坐标轴都隐藏,只保留底部的星期标签。borderData隐藏边框。这种简洁设计让图表更清爽,用户关注数据本身而非坐标轴。

柱状图数据

定义每天的学习数据:

dart 复制代码
                  barGroups: [
                    _makeBarGroup(0, 8),
                    _makeBarGroup(1, 12),
                    _makeBarGroup(2, 6),
                    _makeBarGroup(3, 15),
                    _makeBarGroup(4, 10),
                    _makeBarGroup(5, 18),
                    _makeBarGroup(6, 5),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

7个柱子代表一周7天,第一个参数是索引(0-6),第二个参数是学习数量。实际项目中应该从服务器或数据库获取真实数据。这种数据展示让用户看到每天的学习波动。

柱子构建

封装柱子的构建逻辑:

dart 复制代码
  BarChartGroupData _makeBarGroup(int x, double y) {
    return BarChartGroupData(
      x: x,
      barRods: [
        BarChartRodData(
          toY: y,
          color: const Color(0xFF00897B),
          width: 20.w,
          borderRadius: BorderRadius.vertical(top: Radius.circular(4.r)),
        ),
      ],
    );
  }

BarChartGroupData定义一组柱子,x是横坐标,barRods是柱子列表。BarChartRodData定义单个柱子,toY是高度,color是颜色,width是宽度。顶部圆角让柱子更柔和

分类进度

构建分类学习进度:

dart 复制代码
  Widget _buildCategoryProgress() {
    final categories = [
      {'name': '基础问候', 'progress': 0.8, 'count': '16/20'},
      {'name': '数字手语', 'progress': 0.6, 'count': '12/20'},
      {'name': '日常用语', 'progress': 0.4, 'count': '12/30'},
      {'name': '情感表达', 'progress': 0.3, 'count': '7/25'},
    ];

定义4个分类的进度数据,每个包含名称、进度百分比和数量。进度从0到1表示完成度。这种数据驱动的方式便于添加或删除分类。

分类进度卡片

构建分类进度的容器:

dart 复制代码
    return Card(
      child: Padding(
        padding: EdgeInsets.all(16.w),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('分类进度', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold)),
            SizedBox(height: 16.h),

Card包裹分类进度,标题用粗体显示。crossAxisAlignment.start让内容左对齐。这个区域展示各个分类的详细进度,帮助用户了解哪些分类需要加强

分类进度项

使用map生成进度条:

dart 复制代码
            ...categories.map((cat) => Padding(
              padding: EdgeInsets.only(bottom: 12.h),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(cat['name'] as String, style: TextStyle(fontSize: 14.sp)),
                      Text(cat['count'] as String, style: TextStyle(fontSize: 12.sp, color: Colors.grey)),
                    ],
                  ),
                  SizedBox(height: 4.h),

...展开运算符将map结果插入列表。顶部显示分类名称和数量,左右两端对齐。数量用灰色小字显示,表示这是辅助信息

线性进度条

显示分类的进度条:

dart 复制代码
                  LinearProgressIndicator(
                    value: cat['progress'] as double,
                    backgroundColor: Colors.grey[200],
                    valueColor: const AlwaysStoppedAnimation(Color(0xFF00897B)),
                  ),
                ],
              ),
            )).toList(),
          ],
        ),
      ),
    );
  }

LinearProgressIndicator显示线性进度条,value是进度值(0-1),backgroundColor是背景色,valueColor是进度颜色。AlwaysStoppedAnimation让颜色保持不变。这种进度条比数字更直观。

详细数据

构建详细统计数据:

dart 复制代码
  Widget _buildDetailStats(BuildContext context) {
    return Card(
      child: Padding(
        padding: EdgeInsets.all(16.w),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('详细数据', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold)),
            SizedBox(height: 16.h),
            _buildDetailRow('测验次数', '28次'),
            _buildDetailRow('平均正确率', '85%'),
            _buildDetailRow('最高连续天数', '15天'),
            _buildDetailRow('获得积分', '1280分'),
            _buildDetailRow('解锁成就', '6个'),
          ],
        ),
      ),
    );
  }

Card包裹详细数据,标题用粗体显示。5个数据项调用_buildDetailRow方法构建。这些数据提供更全面的统计信息,满足用户深入了解的需求。

详细数据行

封装数据行的构建逻辑:

dart 复制代码
  Widget _buildDetailRow(String label, String value) {
    return Padding(
      padding: EdgeInsets.symmetric(vertical: 8.h),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(label, style: TextStyle(fontSize: 14.sp, color: Colors.grey[600])),
          Text(value, style: TextStyle(fontSize: 14.sp, fontWeight: FontWeight.bold)),
        ],
      ),
    );
  }
}

Row横向排列标签和数值,mainAxisAlignment.spaceBetween让它们分布在两端。标签用灰色,数值用粗体黑色。这种左右对齐的布局清晰易读,是数据展示的经典设计。

fl_chart库的使用

强大的图表库:

dart 复制代码
import 'package:fl_chart/fl_chart.dart';

BarChart(
  BarChartData(
    alignment: BarChartAlignment.spaceAround,
    maxY: 20,
    barGroups: [...],
  ),
)

fl_chart是Flutter中功能最强大的图表库之一,支持折线图、柱状图、饼图等多种图表类型。API设计合理,自定义能力强。使用第三方库可以快速实现复杂的图表功能。

BarChartData的配置

丰富的配置选项:

dart 复制代码
BarChartData(
  alignment: BarChartAlignment.spaceAround,  // 柱子对齐方式
  maxY: 20,                                   // Y轴最大值
  barTouchData: BarTouchData(enabled: false), // 触摸交互
  titlesData: FlTitlesData(...),             // 坐标轴标题
  borderData: FlBorderData(show: false),      // 边框
  barGroups: [...],                           // 柱子数据
)

每个参数都有明确的作用,通过组合这些参数可以实现各种样式的柱状图。这种声明式配置让代码清晰易懂。

getTitlesWidget自定义标题

自定义坐标轴标题:

dart 复制代码
getTitlesWidget: (value, meta) {
  const days = ['一', '二', '三', '四', '五', '六', '日'];
  return Text(days[value.toInt()], style: TextStyle(fontSize: 12.sp));
},

getTitlesWidget回调函数接收值和元数据,返回标题组件。这里将索引(0-6)映射为中文星期。这种自定义能力让图表可以适应各种需求。

LinearProgressIndicator的使用

简单的进度条组件:

dart 复制代码
LinearProgressIndicator(
  value: cat['progress'] as double,
  backgroundColor: Colors.grey[200],
  valueColor: const AlwaysStoppedAnimation(Color(0xFF00897B)),
),

LinearProgressIndicator是Flutter内置的进度条组件,value是进度值(0-1),backgroundColor是背景色,valueColor是进度颜色。AlwaysStoppedAnimation包裹颜色让它保持不变。这个组件简单易用,适合展示进度。

展开运算符的应用

简化列表插入:

dart 复制代码
...categories.map((cat) => Padding(...)).toList(),
_buildDetailRow('测验次数', '28次'),
_buildDetailRow('平均正确率', '85%'),

...展开运算符将map返回的列表展开,插入到父列表中。这比先创建列表再用addAll添加更简洁。展开运算符是Dart的语法糖,让代码更优雅。

数据驱动的UI

根据数据动态生成UI:

dart 复制代码
final categories = [
  {'name': '基础问候', 'progress': 0.8, 'count': '16/20'},
  // ...
];
...categories.map((cat) {
  return LinearProgressIndicator(value: cat['progress'] as double);
}).toList(),

UI完全由数据驱动,修改数据就能改变显示。添加新分类只需在数组中增加一项,不用修改UI代码。这种数据驱动的设计让代码更灵活,易于维护。

响应式布局

使用flutter_screenutil适配屏幕:

dart 复制代码
fontSize: 18.sp,
padding: EdgeInsets.all(20.w),
height: 200.h,
width: 20.w,

.sp用于字号,.w.h用于尺寸和间距。这些单位会根据屏幕尺寸自动缩放,确保在不同设备上比例一致。一套代码适配所有屏幕。

小结

学习统计页面通过概览卡片展示关键指标,柱状图可视化每周学习情况。分类进度用进度条展示各分类完成度,详细数据提供全面的统计信息。整体设计注重数据可视化和信息层次,帮助用户全面了解学习效果。


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

相关推荐
2501_944525547 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 预算详情页面
android·开发语言·前端·javascript·flutter·ecmascript
雨季6667 小时前
Flutter 三端应用实战:OpenHarmony 简易“动态主题切换卡片”交互模式
flutter·ui·交互·dart
lxl13077 小时前
学习C++(5)运算符重载+赋值运算符重载
学习
向哆哆8 小时前
构建健康档案管理快速入口:Flutter × OpenHarmony 跨端开发实战
flutter·开源·鸿蒙·openharmony·开源鸿蒙
清蒸鳜鱼8 小时前
【Mobile Agent——Droidrun】MacOS+Android配置、使用指南
android·macos·mobileagent
mocoding8 小时前
使用Flutter强大的图标库fl_chart优化鸿蒙版天气预报温度、降水量、湿度展示
flutter·华为·harmonyos
AutumnorLiuu8 小时前
C++并发编程学习(一)——线程基础
开发语言·c++·学习
CS创新实验室8 小时前
关于 Moltbot 的学习总结笔记
笔记·学习·clawdbot·molbot
2501_915918418 小时前
HTTPS 代理失效,启用双向认证(mTLS)的 iOS 应用网络怎么抓包调试
android·网络·ios·小程序·https·uni-app·iphone
向哆哆8 小时前
构建智能健康档案管理与预约挂号系统:Flutter × OpenHarmony 跨端开发实践
flutter·开源·鸿蒙·openharmony·开源鸿蒙