在这里插入图片描述

积分系统是社团管理应用中激励用户参与的重要机制,用户可以通过参加活动获取积分。这篇文章带大家实现我的积分模块。

页面结构搭建

积分页面用StatelessWidget来实现:

class PointsPage extends StatelessWidget {
  const PointsPage({super.key});

页面不需要维护内部状态,所有数据都从Provider获取。
const构造函数可以让Flutter在重建时复用Widget实例。

导入依赖包

在文件开头导入需要的包:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

material.dart提供Material Design风格的组件。
provider用于状态管理。

还需要导入项目内的文件:

import '../../providers/app_provider.dart';

app_provider包含用户积分数据。
使用相对路径引入,…/…/表示向上两级目录。

模拟积分历史数据

在build方法中定义积分历史数据:

  
  Widget build(BuildContext context) {
    final pointsHistory = [
      {
        'title': '参加ACM培训', 
        'points': 20, 
        'time': '2024-01-10', 
        'type': 'earn'
      },
      {
        'title': '完成任务', 
        'points': 10, 
        'time': '2024-01-08', 
        'type': 'earn'
      },

积分历史用Map列表模拟,包含标题、积分数、时间和类型。
实际项目中这些数据应该从后端获取。

继续添加更多记录:

      {
        'title': '签到奖励', 
        'points': 5, 
        'time': '2024-01-07', 
        'type': 'earn'
      },
      {
        'title': '兑换礼品', 
        'points': -50, 
        'time': '2024-01-05', 
        'type': 'spend'
      },
      {
        'title': '参加摄影活动', 
        'points': 30, 
        'time': '2024-01-03', 
        'type': 'earn'
      },
      {
        'title': '邀请新成员', 
        'points': 15, 
        'time': '2024-01-01', 
        'type': 'earn'
      },
    ];

type字段区分获取(earn)和消费(spend)。
消费记录的points为负数。

构建页面骨架

使用Scaffold搭建基本结构:

    return Scaffold(
      appBar: AppBar(
        title: const Text('我的积分')
      ),

Scaffold是Material Design的基础布局组件。
标题直接写"我的积分",简洁明了。

数据监听

使用Consumer监听AppProvider的数据变化:

      body: Consumer<AppProvider>(
        builder: (context, provider, _) {
          return Column(
            children: [

Consumer会在数据变化时自动重建子组件。
Column纵向排列积分卡片和明细列表。

积分展示卡片

页面顶部显示当前积分:

              Container(
                padding: const EdgeInsets.all(32),
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                    colors: [Color(0xFF4A90E2), Color(0xFF357ABD)],
                    begin: Alignment.topLeft,
                    end: Alignment.bottomRight,
                  ),
                ),

使用渐变背景让积分区域更加醒目。
32像素的padding让内容有足够的呼吸空间。

积分数值显示:

                child: Column(
                  children: [
                    const Text(
                      '当前积分', 
                      style: TextStyle(
                        color: Colors.white70, 
                        fontSize: 16
                      )
                    ),
                    const SizedBox(height: 8),
                    Text(
                      '${provider.currentUser.points}', 
                      style: const TextStyle(
                        color: Colors.white, 
                        fontSize: 48, 
                        fontWeight: FontWeight.bold
                      )
                    ),
                    const SizedBox(height: 16),

48像素的超大字号让积分数值成为视觉焦点。
白色粗体在蓝色背景上非常醒目。

操作按钮区域

添加积分兑换和规则查看按钮:

                    Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        _buildActionButton(
                          Icons.card_giftcard, 
                          '积分兑换', 
                          () {
                            ScaffoldMessenger.of(context).showSnackBar(
                              const SnackBar(
                                content: Text('兑换功能开发中')
                              )
                            );
                          }
                        ),
                        const SizedBox(width: 32),
                        _buildActionButton(
                          Icons.rule, 
                          '积分规则', 
                          () {
                            _showPointsRules(context);
                          }
                        ),
                      ],
                    ),
                  ],
                ),
              ),

两个按钮横向排列,间距32像素。
积分兑换暂时显示开发中提示。

明细标题栏

积分明细区域的标题栏:

              Padding(
                padding: const EdgeInsets.all(16),
                child: Row(
                  children: [
                    const Text(
                      '积分明细', 
                      style: TextStyle(
                        fontWeight: FontWeight.bold, 
                        fontSize: 16
                      )
                    ),
                    const Spacer(),
                    TextButton(
                      onPressed: () {}, 
                      child: const Text('全部记录')
                    ),
                  ],
                ),
              ),

左侧显示标题,右侧显示查看全部按钮。
Spacer让两者分别靠左和靠右对齐。

积分明细列表

使用ListView.builder构建明细列表:

              Expanded(
                child: ListView.builder(
                  padding: const EdgeInsets.symmetric(horizontal: 16),
                  itemCount: pointsHistory.length,
                  itemBuilder: (context, index) {
                    final item = pointsHistory[index];
                    final isEarn = item['type'] == 'earn';

Expanded让列表占据剩余空间。
isEarn变量判断是获取还是消费积分。

明细卡片设计

每条明细用Card和ListTile组合展示:

                    return Card(
                      margin: const EdgeInsets.only(bottom: 8),
                      child: ListTile(
                        leading: CircleAvatar(
                          backgroundColor: isEarn 
                              ? Colors.green.withOpacity(0.1) 
                              : Colors.red.withOpacity(0.1),
                          child: Icon(
                            isEarn ? Icons.add : Icons.remove,
                            color: isEarn ? Colors.green : Colors.red,
                          ),
                        ),

获取积分用绿色加号图标,消费积分用红色减号图标。
颜色区分让用户一眼就能识别记录类型。

明细信息显示:

                        title: Text(item['title'] as String),
                        subtitle: Text(item['time'] as String),
                        trailing: Text(
                          '${isEarn ? '+' : ''}${item['points']}',
                          style: TextStyle(
                            fontWeight: FontWeight.bold,
                            fontSize: 16,
                            color: isEarn ? Colors.green : Colors.red,
                          ),
                        ),
                      ),
                    );
                  },
                ),
              ),
            ],
          );
        },
      ),
    );
  }

积分数值显示正负号,获取显示加号,消费显示负数。
颜色和图标保持一致。

操作按钮组件

定义构建操作按钮的方法:

  Widget _buildActionButton(
    IconData icon, 
    String label, 
    VoidCallback onTap
  ) {
    return GestureDetector(
      onTap: onTap,
      child: Column(
        children: [
          Container(
            padding: const EdgeInsets.all(12),
            decoration: BoxDecoration(
              color: Colors.white.withOpacity(0.2),
              borderRadius: BorderRadius.circular(12),
            ),
            child: Icon(icon, color: Colors.white, size: 24),
          ),
          const SizedBox(height: 8),
          Text(
            label, 
            style: const TextStyle(
              color: Colors.white, 
              fontSize: 12
            )
          ),
        ],
      ),
    );
  }

按钮使用半透明白色背景,图标和文字都是白色。
GestureDetector处理点击事件。

积分规则弹窗

定义显示积分规则的方法:

  void _showPointsRules(BuildContext context) {
    showModalBottomSheet(
      context: context,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(
          top: Radius.circular(16)
        )
      ),
      builder: (ctx) => Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              '积分规则', 
              style: TextStyle(
                fontSize: 20, 
                fontWeight: FontWeight.bold
              )
            ),
            const SizedBox(height: 16),

使用BottomSheet从底部弹出,顶部有圆角。
mainAxisSize设为min让弹窗高度自适应内容。

规则列表:

            _buildRuleItem('参加活动', '+10~30积分'),
            _buildRuleItem('完成任务', '+5~20积分'),
            _buildRuleItem('每日签到', '+5积分'),
            _buildRuleItem('邀请新成员', '+15积分'),
            _buildRuleItem('发布优质内容', '+10积分'),
            const SizedBox(height: 16),
            const Text(
              '积分可用于兑换社团周边、活动优先报名等权益', 
              style: TextStyle(
                color: Colors.grey, 
                fontSize: 13
              )
            ),
            const SizedBox(height: 20),
          ],
        ),
      ),
    );
  }

列出常见的积分获取方式和对应的积分数。
底部说明积分的用途。

规则行组件

定义构建规则行的方法:

  Widget _buildRuleItem(String action, String points) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(action),
          Text(
            points, 
            style: const TextStyle(
              color: Color(0xFF4A90E2), 
              fontWeight: FontWeight.bold
            )
          ),
        ],
      ),
    );
  }
}

行为描述靠左,积分数靠右。
积分数用蓝色粗体突出显示。

积分系统的激励作用

积分系统是提升用户活跃度的有效手段。
通过设置合理的积分获取规则,可以引导用户参与社团活动。

积分兑换功能给用户提供了使用积分的出口。
形成完整的激励闭环。

颜色区分的设计考虑

获取积分使用绿色,消费积分使用红色。
这是符合用户直觉的设计。

绿色通常代表正面、增加,红色代表负面、减少。
这种颜色编码让用户无需阅读文字就能快速理解。

小结

积分页面通过大字号展示当前积分余额,让用户一目了然。操作按钮提供积分兑换和规则查看的入口。积分明细列表显示获取和消费记录,使用颜色区分不同类型。积分规则弹窗说明各种获取积分的方式。


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

Logo

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

更多推荐