Flutter for OpenHarmony 社团管理App实战 - 资产管理实现

资产管理是社团财务管理的重要组成部分,用于记录和管理社团的各种设备和物资。这篇文章带大家实现资产管理模块。

页面结构搭建

资产管理页面用StatelessWidget来实现:

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

页面不需要维护内部状态,所有数据都从Provider获取。

const构造函数可以让Flutter在重建时复用Widget实例。

导入依赖包

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

dart 复制代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:intl/intl.dart';

material.dart提供Material Design风格的组件。

provider用于状态管理,intl用于日期格式化。

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

dart 复制代码
import '../../providers/app_provider.dart';

app_provider包含资产数据。

使用相对路径引入,.../.../表示向上两级目录。

构建页面骨架

使用Scaffold搭建基本结构:

dart 复制代码
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('资产管理')
      ),

Scaffold是Material Design的基础布局组件。

标题直接写"资产管理",简洁明了。

数据监听

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

dart 复制代码
      body: Consumer<AppProvider>(
        builder: (context, provider, _) {
          final assets = provider.assets
              .where((a) => a.clubId == 'club001')
              .toList();
          final totalValue = assets.fold(
            0.0, 
            (sum, a) => sum + a.value
          );

Consumer会在数据变化时自动重建子组件。

fold方法计算资产总值,遍历列表累加每个资产的价值。

页面布局

使用Column纵向排列统计卡片和列表:

dart 复制代码
          return Column(
            children: [

Column的children包含统计区域和资产列表两部分。

统计区域固定高度,列表区域占据剩余空间。

统计卡片设计

页面顶部显示资产统计信息:

dart 复制代码
              Container(
                padding: const EdgeInsets.all(20),
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                    colors: [Color(0xFF4A90E2), Color(0xFF357ABD)],
                    begin: Alignment.topLeft,
                    end: Alignment.bottomRight,
                  ),
                ),

使用渐变背景让统计区域更加醒目。

LinearGradient从左上到右下渐变。

统计数据布局:

dart 复制代码
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    Column(
                      children: [
                        const Text(
                          '资产总数', 
                          style: TextStyle(color: Colors.white70)
                        ),
                        const SizedBox(height: 4),
                        Text(
                          '${assets.length}项', 
                          style: const TextStyle(
                            color: Colors.white, 
                            fontSize: 24, 
                            fontWeight: FontWeight.bold
                          )
                        ),
                      ],
                    ),

左侧显示资产总数,标签用半透明白色。

数值用白色粗体大字,24像素字号。

分隔线和总值:

dart 复制代码
                    Container(
                      width: 1, 
                      height: 40, 
                      color: Colors.white30
                    ),
                    Column(
                      children: [
                        const Text(
                          '资产总值', 
                          style: TextStyle(color: Colors.white70)
                        ),
                        const SizedBox(height: 4),
                        Text(
                          '¥${totalValue.toStringAsFixed(0)}', 
                          style: const TextStyle(
                            color: Colors.white, 
                            fontSize: 24, 
                            fontWeight: FontWeight.bold
                          )
                        ),
                      ],
                    ),
                  ],
                ),
              ),

分隔线用半透明白色,高度40像素。

资产总值用toStringAsFixed(0)格式化为整数。

资产列表区域

使用Expanded让列表占据剩余空间:

dart 复制代码
              Expanded(
                child: assets.isEmpty
                    ? const Center(
                        child: Text(
                          '暂无资产', 
                          style: TextStyle(color: Colors.grey)
                        )
                      )

空状态时显示友好的提示文字。

Expanded会让子组件填充Column中的剩余空间。

使用ListView.builder构建列表:

dart 复制代码
                    : ListView.builder(
                        padding: const EdgeInsets.all(16),
                        itemCount: assets.length,
                        itemBuilder: (context, index) {
                          final asset = assets[index];

ListView.builder是懒加载列表,性能更好。

padding设置16像素内边距。

资产卡片设计

每个资产用Card和ListTile组合展示:

dart 复制代码
                          return Card(
                            margin: const EdgeInsets.only(bottom: 12),
                            child: ListTile(
                              leading: CircleAvatar(
                                backgroundColor: const Color(0xFF4A90E2)
                                    .withOpacity(0.1),
                                child: Icon(
                                  _getCategoryIcon(asset.category), 
                                  color: const Color(0xFF4A90E2)
                                ),
                              ),

leading位置放置分类图标。

不同分类使用不同的图标。

资产基本信息

显示资产名称和分类数量:

dart 复制代码
                              title: Text(asset.name),
                              subtitle: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Text(
                                    '${asset.category} · 数量: ${asset.quantity}'
                                  ),
                                  Text(
                                    '位置: ${asset.location}', 
                                    style: const TextStyle(fontSize: 12)
                                  ),
                                ],
                              ),

subtitle用Column显示两行信息。

第一行是分类和数量,第二行是存放位置。

价值和状态显示

trailing位置显示资产价值和状态:

dart 复制代码
                              trailing: Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                crossAxisAlignment: CrossAxisAlignment.end,
                                children: [
                                  Text(
                                    '¥${asset.value.toStringAsFixed(0)}', 
                                    style: const TextStyle(
                                      fontWeight: FontWeight.bold, 
                                      color: Color(0xFF4A90E2)
                                    )
                                  ),

价值用蓝色粗体显示。

toStringAsFixed(0)格式化为整数。

状态标签:

dart 复制代码
                                  Container(
                                    padding: const EdgeInsets.symmetric(
                                      horizontal: 6, 
                                      vertical: 2
                                    ),
                                    decoration: BoxDecoration(
                                      color: asset.status == '正常' 
                                          ? Colors.green.withOpacity(0.1) 
                                          : Colors.orange.withOpacity(0.1),
                                      borderRadius: BorderRadius.circular(4),
                                    ),
                                    child: Text(
                                      asset.status, 
                                      style: TextStyle(
                                        color: asset.status == '正常' 
                                            ? Colors.green 
                                            : Colors.orange, 
                                        fontSize: 10
                                      )
                                    ),
                                  ),
                                ],
                              ),
                              onTap: () => _showAssetDetail(context, asset),
                            ),
                          );
                        },
                      ),
              ),
            ],
          );
        },
      ),
    );
  }

正常状态用绿色,其他状态用橙色。

点击卡片调用_showAssetDetail显示详情。

分类图标映射

定义获取分类图标的方法:

dart 复制代码
  IconData _getCategoryIcon(String category) {
    switch (category) {
      case '电子设备':
        return Icons.computer;
      case '摄影器材':
        return Icons.camera_alt;
      case '体育器材':
        return Icons.sports_basketball;
      case '图书':
        return Icons.book;
      default:
        return Icons.inventory;
    }
  }

不同分类使用不同的图标,让用户快速识别资产类型。

default分支使用通用的库存图标。

详情弹窗实现

使用BottomSheet显示资产详情:

dart 复制代码
  void _showAssetDetail(BuildContext context, asset) {
    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: [
            Text(
              asset.name, 
              style: const TextStyle(
                fontSize: 20, 
                fontWeight: FontWeight.bold
              )
            ),
            const SizedBox(height: 16),

BottomSheet从底部弹出,顶部有圆角。

mainAxisSize设为min让弹窗高度自适应内容。

详情信息列表:

dart 复制代码
            _buildDetailRow('分类', asset.category),
            _buildDetailRow('数量', '${asset.quantity}'),
            _buildDetailRow('存放位置', asset.location),
            _buildDetailRow('状态', asset.status),
            _buildDetailRow(
              '价值', 
              '¥${asset.value.toStringAsFixed(2)}'
            ),
            _buildDetailRow(
              '购入日期', 
              DateFormat('yyyy-MM-dd').format(asset.purchaseDate)
            ),
            const SizedBox(height: 20),
          ],
        ),
      ),
    );
  }

使用_buildDetailRow方法统一构建每一行信息。

价值显示两位小数,更加精确。

详情行组件

定义构建详情行的方法:

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

标签用灰色,值用中等粗细的黑色。

spaceBetween让标签和值分别靠左和靠右对齐。

渐变背景的设计考虑

统计区域使用渐变背景而不是纯色背景。

可以增加视觉层次感,让这个区域更加突出。

蓝色系的渐变和整体风格保持一致。

同时吸引用户注意重要的统计信息。

资产状态的重要性

资产状态是资产管理中的重要信息。

正常状态表示资产可以正常使用。

其他状态如维修中、报废等需要特别关注。

使用不同颜色的标签让用户快速识别需要处理的资产。

小结

资产管理页面通过统计卡片和列表的形式展示社团资产信息。顶部显示资产总数和总值,列表显示每个资产的详细信息。不同分类使用不同图标,不同状态使用不同颜色标签。点击资产可以查看完整的详情信息。


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

相关推荐
senijusene2 小时前
数据结构与算法:栈的基本概念,顺序栈与链式栈的详细实现
c语言·开发语言·算法·链表
naruto_lnq2 小时前
分布式日志系统实现
开发语言·c++·算法
索荣荣2 小时前
Java正向代理与反向代理实战指南
java·开发语言
郑州光合科技余经理2 小时前
可独立部署的Java同城O2O系统架构:技术落地
java·开发语言·前端·后端·小程序·系统架构·uni-app
小哥Mark2 小时前
各种Flutter拖拽交互组件助力鸿蒙应用个性化
flutter·交互·harmonyos
啊我不会诶2 小时前
Codeforces Round 1071 (Div. 3) vp补题
开发语言·学习·算法
json{shen:"jing"}2 小时前
js收官总概述
开发语言·python
froginwe112 小时前
Java 文档注释
开发语言