You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何复用ListView ItemBuilder并实现科目独立存储成绩功能?

解决GPA应用的两个核心问题

一、解决科目成绩同步问题

你的问题根源在于所有科目共用同一个全局gradeObjects列表,导致添加成绩时会同步到所有科目。解决方案是创建独立的科目数据模型,让每个科目自己管理成绩列表。

1. 定义Subject数据模型

创建一个类封装科目名称和专属成绩列表:

class Subject {
  final String name;
  List<int> grades;

  Subject({required this.name, List<int>? grades}) : grades = grades ?? [];
}

2. 重构科目列表

将原来的字符串列表替换为Subject实例列表:

List<Subject> subjects = [
  Subject(name: 'Mathematik'),
  Subject(name: 'Deutsch'),
  Subject(name: 'Englisch'),
  Subject(name: 'Geschichte'),
  Subject(name: 'Geographie'),
  Subject(name: 'WTH'),
  Subject(name: 'GK'),
  Subject(name: 'Religion'),
  Subject(name: 'Physik'),
  Subject(name: 'Chemie'),
  Subject(name: 'Informatik'),
  Subject(name: 'Sport'),
  Subject(name: 'Kunst'),
  Subject(name: 'Spanisch/Russisch'),
];

3. 独立操作科目成绩

现在可以针对单个科目添加/管理成绩,不会影响其他科目:

// 给指定科目添加成绩
void addGradeToSubject(Subject subject, int grade) {
  setState(() {
    subject.grades.add(grade);
  });
}

// 计算整体GPA(遍历所有科目成绩)
double calculateOverallGPA() {
  List<int> allGrades = [];
  for (var subject in subjects) {
    allGrades.addAll(subject.grades);
  }
  if (allGrades.isEmpty) return 0.0;
  return allGrades.fold(0.0, (sum, grade) => sum + grade) / allGrades.length;
}

二、复用ListView ItemBuilder

要复用ListView.builder,可以将其封装为通用组件,通过参数传递列表数据、item构建逻辑和回调。

1. 创建通用列表组件

class ReusableListView<T> extends StatelessWidget {
  final List<T> items;
  final Widget Function(BuildContext context, T item, int index, VoidCallback? onAction) itemBuilder;
  final void Function(int index)? onAction;

  const ReusableListView({
    super.key,
    required this.items,
    required this.itemBuilder,
    this.onAction,
  });

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        final item = items[index];
        return itemBuilder(
          context,
          item,
          index,
          onAction != null ? () => onAction!(index) : null,
        );
      },
    );
  }
}

2. 复用组件展示科目列表

调整singleSubject组件,接收科目名称、成绩列表和操作回调,然后通过通用列表组件渲染:

// 重构singleSubject组件,支持独立成绩展示和操作
Widget singleSubject(
  String subjectName,
  List<int> grades,
  VoidCallback? onDelete,
  Function(int) onAddGrade,
) {
  return Card(
    child: Padding(
      padding: const EdgeInsets.all(8.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(subjectName, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
              if (onDelete != null)
                IconButton(icon: const Icon(Icons.delete), onPressed: onDelete),
            ],
          ),
          const SizedBox(height: 8),
          // 展示当前科目已有的成绩
          Wrap(
            spacing: 8,
            children: grades.map((grade) => Chip(label: Text('$grade'))).toList(),
          ),
          const SizedBox(height: 8),
          // 添加成绩按钮(可替换为输入框弹窗)
          ElevatedButton(
            onPressed: () => onAddGrade(4), // 示例值,实际替换为用户输入逻辑
            child: const Text('添加成绩'),
          ),
        ],
      ),
    ),
  );
}

// 使用通用列表组件渲染科目
ReusableListView<Subject>(
  items: subjects,
  onAction: (index) => deleteItem(index),
  itemBuilder: (context, subject, index, onDelete) {
    return singleSubject(
      subject.name,
      subject.grades,
      onDelete,
      (int grade) => addGradeToSubject(subject, grade),
    );
  },
)

这样你的ReusableListView组件可以复用在任何需要列表展示的场景,只要传入对应类型的列表数据和item构建逻辑即可。

内容的提问来源于stack exchange,提问作者Vince

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 19:01:18