flutter_for_openharmony手语学习app实战+学习进度实现

学习进度页面帮助用户了解整体学习情况,通过可视化图表展示各个维度的进度。本文介绍如何实现一个学习进度页面,包括总体进度、分类进度和最近动态。

导入依赖包

首先导入必要的依赖:

dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:percent_indicator/percent_indicator.dart';

这三个包分别提供Flutter基础组件、屏幕适配和进度条组件。percent_indicator是第三方库,需要在pubspec.yaml中添加依赖。

页面基础结构

定义学习进度页面:

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('学习进度'),
        elevation: 0,
      ),

AppBarelevation设为0去掉阴影,让界面更简洁。标题直接显示"学习进度",用户一眼就知道当前页面的功能。

滚动容器

构建可滚动的内容区域:

dart 复制代码
      body: SingleChildScrollView(
        padding: EdgeInsets.all(16.w),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            _buildOverallProgress(),
            SizedBox(height: 20.h),
            _buildCategoryProgress(),
            SizedBox(height: 20.h),
            _buildRecentActivity(),
          ],
        ),
      ),
    );
  }

使用StatelessWidget构建页面,SingleChildScrollView让内容可以滚动。Column纵向排列三个区域:总体进度、分类进度和最近动态。crossAxisAlignment.start让内容左对齐,SizedBox控制区域间距。这种分区设计让信息层次清晰。

总体进度卡片容器

构建顶部的总体进度展示:

dart 复制代码
  Widget _buildOverallProgress() {
    return Card(
      elevation: 2,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(16.r),
      ),
      child: Padding(
        padding: EdgeInsets.all(20.w),
        child: Column(
          children: [

Cardelevation设为2提供轻微阴影,shape设置圆角为16.rPadding给内容区域加上内边距,让布局不会太紧凑。

圆形进度指示器

显示总体学习进度:

dart 复制代码
            CircularPercentIndicator(
              radius: 70.r,
              lineWidth: 12.w,
              percent: 0.45,
              center: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(
                    '45%',
                    style: TextStyle(
                      fontSize: 28.sp,
                      fontWeight: FontWeight.bold,
                      color: const Color(0xFF00897B),
                    ),
                  ),
                  SizedBox(height: 4.h),
                  Text(
                    '总进度',
                    style: TextStyle(
                      fontSize: 12.sp,
                      color: Colors.grey,
                    ),
                  ),
                ],
              ),
              progressColor: const Color(0xFF00897B),
              backgroundColor: Colors.grey[200]!,
              circularStrokeCap: CircularStrokeCap.round,
            ),
            SizedBox(height: 20.h),

CircularPercentIndicator显示圆形进度条,半径70.r线宽12.w。中心显示百分比数字和"总进度"标签,数字用大字号粗体突出。进度条用主题色,背景用浅灰色。circularStrokeCap.round让进度条两端呈圆形,视觉效果更柔和。这种圆形进度条比数字更直观,用户一眼就能看出完成情况。

统计数据行

显示三个关键指标:

dart 复制代码
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                _buildProgressStat('已学词汇', '156', Icons.school),
                _buildProgressStat('总词汇', '350', Icons.library_books),
                _buildProgressStat('学习天数', '28', Icons.calendar_today),
              ],
            ),
          ],
        ),
      ),
    );
  }

Row横向排列三个统计项,mainAxisAlignment.spaceAround让它们均匀分布。每个统计项包含图标、数值和标签,调用_buildProgressStat方法构建。这种数据可视化让用户快速了解学习成果。

统计项构建

封装统计项的构建逻辑:

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

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

分类进度区域

构建分类进度展示:

dart 复制代码
  Widget _buildCategoryProgress() {
    final categories = [
      {'name': '基础问候', 'learned': 18, 'total': 20, 'color': Colors.blue},
      {'name': '数字手语', 'learned': 15, 'total': 20, 'color': Colors.green},
      {'name': '日常用语', 'learned': 20, 'total': 35, 'color': Colors.orange},
      {'name': '情感表达', 'learned': 12, 'total': 25, 'color': Colors.pink},
      {'name': '家庭成员', 'learned': 8, 'total': 15, 'color': Colors.purple},
      {'name': '紧急求助', 'learned': 6, 'total': 10, 'color': Colors.red},
    ];

定义6个分类的进度数据,每个分类包含名称、已学数量、总数量和颜色。不同分类用不同颜色区分,让进度条更丰富多彩。实际项目中应该从服务器或数据库获取真实数据。

分类进度卡片

构建分类进度的容器:

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) {
              final progress = (cat['learned'] as int) / (cat['total'] as int);
              return Padding(
                padding: EdgeInsets.only(bottom: 16.h),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text(cat['name'] as String, style: TextStyle(fontSize: 14.sp)),
                        Text('${cat['learned']}/${cat['total']}', style: TextStyle(fontSize: 12.sp, color: Colors.grey)),
                      ],
                    ),
                    SizedBox(height: 6.h),

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

线性进度条

显示分类的进度条:

dart 复制代码
                    LinearPercentIndicator(
                      lineHeight: 8.h,
                      percent: progress,
                      backgroundColor: Colors.grey[200],
                      progressColor: cat['color'] as Color,
                      barRadius: Radius.circular(4.r),
                      padding: EdgeInsets.zero,
                    ),
                  ],
                ),
              );
            }).toList(),
          ],
        ),
      ),
    );
  }

LinearPercentIndicator显示线性进度条,高度8.h,进度颜色根据分类动态变化。barRadius设置圆角,padding设为零去掉多余空白。不同颜色的进度条让列表更生动有趣,也帮助用户快速识别不同分类。

最近动态区域

构建最近动态展示:

dart 复制代码
  Widget _buildRecentActivity() {
    final activities = [
      {'action': '完成课程', 'content': '你好', 'time': '10分钟前'},
      {'action': '完成测验', 'content': '基础问候测验', 'time': '30分钟前'},
      {'action': '完成课程', 'content': '谢谢', 'time': '1小时前'},
      {'action': '获得成就', 'content': '连续学习7天', 'time': '昨天'},
    ];

定义4条最近动态数据,每条包含行为、内容和时间。动态按时间倒序排列,最新的在最上面。这种时间线设计让用户回顾最近的学习活动。

最近动态卡片

构建动态列表的容器:

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: 12.h),

Card包裹最近动态,标题用粗体显示。crossAxisAlignment.start让内容左对齐。这个区域展示用户的学习轨迹,增强成就感

动态列表项

使用map生成动态项:

dart 复制代码
            ...activities.map((activity) => ListTile(
              contentPadding: EdgeInsets.zero,
              leading: Container(
                width: 40.w,
                height: 40.w,
                decoration: BoxDecoration(
                  color: const Color(0xFF00897B).withOpacity(0.1),
                  shape: BoxShape.circle,
                ),
                child: Icon(Icons.check, color: const Color(0xFF00897B), size: 20.sp),
              ),

ListTile构建每条动态,contentPadding设为零去掉默认内边距。左侧显示圆形图标,用主题色半透明背景和对勾图标。这种统一的图标让列表整齐一致。

动态内容

显示行为、内容和时间:

dart 复制代码
              title: Text(activity['action']!, style: TextStyle(fontSize: 14.sp)),
              subtitle: Text(activity['content']!, style: TextStyle(fontSize: 12.sp)),
              trailing: Text(activity['time']!, style: TextStyle(fontSize: 11.sp, color: Colors.grey)),
            )).toList(),
          ],
        ),
      ),
    );
  }
}

title显示行为(完成课程、完成测验等),subtitle显示具体内容,trailing显示时间。时间用灰色小字显示,表示这是次要信息。这种布局让用户快速浏览最近的学习活动。

CircularPercentIndicator的应用

圆形进度条的优势:

dart 复制代码
CircularPercentIndicator(
  radius: 70.r,
  lineWidth: 12.w,
  percent: 0.45,
  center: Column(...),
  progressColor: const Color(0xFF00897B),
  backgroundColor: Colors.grey[200]!,
)

圆形进度条比数字更直观,视觉冲击力强。中心可以放置自定义内容,比如百分比和标签。进度颜色和背景色可以自定义,适应不同的设计风格。这种可视化组件提升了用户体验。

LinearPercentIndicator的应用

线性进度条的特点:

dart 复制代码
LinearPercentIndicator(
  lineHeight: 8.h,
  percent: progress,
  backgroundColor: Colors.grey[200],
  progressColor: cat['color'] as Color,
  barRadius: Radius.circular(4.r),
  padding: EdgeInsets.zero,
)

线性进度条适合在列表中展示多个进度,占用空间小。圆角设计更柔和,不同颜色区分不同分类。padding设为零让进度条紧贴容器边缘,最大化利用空间

展开运算符的应用

简化列表插入:

dart 复制代码
...categories.map((cat) => ...).toList(),
...activities.map((activity) => ...).toList(),

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

数据驱动的UI

根据数据动态生成UI:

dart 复制代码
final categories = [
  {'name': '基础问候', 'learned': 18, 'total': 20, 'color': Colors.blue},
  // ...
];
...categories.map((cat) {
  final progress = (cat['learned'] as int) / (cat['total'] as int);
  return LinearPercentIndicator(percent: progress, progressColor: cat['color'] as Color);
}).toList(),

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

颜色的多样性

不同分类使用不同颜色:

dart 复制代码
{'name': '基础问候', 'learned': 18, 'total': 20, 'color': Colors.blue},
{'name': '数字手语', 'learned': 15, 'total': 20, 'color': Colors.green},
{'name': '日常用语', 'learned': 20, 'total': 35, 'color': Colors.orange},

蓝色、绿色、橙色、粉色、紫色、红色,6个分类用6种颜色。丰富的颜色让界面更生动有趣,也帮助用户快速识别不同分类。颜色选择要有一定的区分度,避免相近颜色混淆。

信息层次的建立

通过字号、颜色、粗细建立层次:

dart 复制代码
Text('45%', style: TextStyle(fontSize: 28.sp, fontWeight: FontWeight.bold)),  // 主要信息
Text('总进度', style: TextStyle(fontSize: 12.sp, color: Colors.grey)),        // 次要信息
Text(value, style: TextStyle(fontSize: 20.sp, fontWeight: FontWeight.bold)),  // 数值
Text(label, style: TextStyle(fontSize: 11.sp, color: Colors.grey)),           // 标签

主要信息用大字号粗体,次要信息用小字号灰色。这种三级层次让用户快速抓住重点,先看百分比判断整体进度,再看具体数值了解详情。

间距的设计

不同位置使用不同间距:

dart 复制代码
SizedBox(height: 8.h),   // 图标和数值的小间距
SizedBox(height: 16.h),  // 标题和内容的中等间距
SizedBox(height: 20.h),  // 区域之间的大间距

紧密相关的元素用小间距,不同功能区域用大间距。这种间距层次让界面有呼吸感,信息分组清晰,不会显得拥挤或松散。

响应式布局

使用flutter_screenutil适配屏幕:

dart 复制代码
radius: 70.r,
lineWidth: 12.w,
fontSize: 28.sp,
padding: EdgeInsets.all(16.w),

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

小结

学习进度页面通过圆形进度条展示总体进度,统计数据显示关键指标。分类进度用线性进度条和不同颜色区分,最近动态展示学习轨迹。整体设计注重数据可视化和信息层次,帮助用户全面了解学习情况。

进度数据的获取

实际项目中应该从Provider或数据库获取进度数据:

dart 复制代码
final learningProvider = Provider.of<LearningProvider>(context);
final overallProgress = learningProvider.calculateOverallProgress();
final categoryProgress = learningProvider.getCategoryProgress();

使用Provider管理全局学习数据,页面只负责展示。这种数据与UI分离的设计让代码更易维护。

进度计算逻辑

计算总体进度的方法:

dart 复制代码
double calculateOverallProgress() {
  int totalLessons = 0;
  int completedLessons = 0;
  
  for (var category in categories) {
    totalLessons += category.totalLessons;
    completedLessons += category.completedLessons;
  }
  
  return completedLessons / totalLessons;
}

遍历所有分类,累加总课程数和已完成数,计算百分比。这个逻辑应该放在Provider或Model层,而不是UI层。

动画效果优化

为进度条添加动画效果:

dart 复制代码
CircularPercentIndicator(
  radius: 70.r,
  lineWidth: 12.w,
  percent: 0.45,
  animation: true,
  animationDuration: 1200,
  curve: Curves.easeInOut,
  ...
)

animation: true启用动画,animationDuration设置动画时长为1200毫秒。curve设置缓动曲线,让动画更自然。页面打开时进度条会从0动画到目标值,视觉效果更生动

下拉刷新功能

添加下拉刷新更新进度数据:

dart 复制代码
RefreshIndicator(
  onRefresh: () async {
    await learningProvider.refreshProgress();
  },
  child: SingleChildScrollView(
    ...
  ),
)

RefreshIndicator包裹滚动容器,用户下拉时触发onRefresh回调。在回调中调用Provider的刷新方法,重新获取最新数据。这是移动应用的标准交互

空状态处理

当没有学习数据时显示空状态:

dart 复制代码
if (learningProvider.hasNoData) {
  return Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Icon(Icons.school_outlined, size: 80.sp, color: Colors.grey[300]),
        SizedBox(height: 16.h),
        Text('还没有学习记录', style: TextStyle(fontSize: 16.sp, color: Colors.grey)),
        SizedBox(height: 8.h),
        ElevatedButton(
          onPressed: () => Navigator.pushNamed(context, '/learn'),
          child: const Text('开始学习'),
        ),
      ],
    ),
  );
}

空状态显示图标、提示文字和开始学习按钮,引导用户进行首次学习。这种友好的空状态比空白页面体验好得多。

性能优化建议

对于大量数据的处理优化:

dart 复制代码
// 使用const减少重建
const Text('总进度')

// 缓存计算结果
final progress = useMemoized(() => calculateProgress(), [data]);

// 延迟加载非关键数据
Future.delayed(Duration(milliseconds: 300), () {
  loadRecentActivity();
});

合理使用const、缓存计算结果、延迟加载非关键数据,可以显著提升页面性能。特别是在低端设备上,这些优化很重要。


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

相关推荐
吉吉安2 小时前
双层文字扫光效果
前端·javascript·css
2601_949847752 小时前
Flutter for OpenHarmony 剧本杀组队App实战:意见反馈功能实现
flutter
Miguo94well2 小时前
Flutter框架跨平台鸿蒙开发——班级点名APP的开发流程
flutter·华为·harmonyos·鸿蒙
lbb 小魔仙2 小时前
【Harmonyos】开源鸿蒙跨平台训练营DAY7:Flutter鸿蒙实战轮播图搜索框和导航指示器
flutter·开源·harmonyos
小马_xiaoen2 小时前
WebSocket与SSE深度对比与实战 Demo
前端·javascript·网络·websocket·网络协议
九 龙2 小时前
Flutter框架跨平台鸿蒙开发——存款利息计算器APP的开发流程
flutter·华为·harmonyos·鸿蒙
楼田莉子2 小时前
Linux进程间通信——System V系列
linux·服务器·c++·学习·信息与通信
321.。2 小时前
从 0 到 1 实现 Linux 下的线程安全阻塞队列:基于 RAII 与条件变量
linux·开发语言·c++·学习·中间件
晚霞的不甘2 小时前
Flutter for OpenHarmony《智慧字典》 App 底部导航栏深度解析:构建多页面应用的核心骨架
前端·经验分享·flutter·ui·前端框架·知识图谱