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

Flutter射箭计分表添加第二轮计分列的实现求助

解决方案:实现两轮射箭计分表并排布局

先修正你原有代码里的一个明显错误:Target 7绑定了num8controller,Target 20绑定了num7controller,这会导致计分混乱,重构时会一并修复。

核心思路是把单轮的计分区域封装成可复用组件,再用Row将两个单轮组件横向排列,既保持代码整洁,也避免布局嵌套错误。以下是完整的实现代码:

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    const appTitle = 'Twin City Bowmen Score Sheet';
    return MaterialApp(
      title: appTitle,
      home: Scaffold(
        appBar: AppBar(title: const Text(appTitle)),
        body: const ScoreSheet(),
      ),
    );
  }
}

class ScoreSheet extends StatefulWidget {
  const ScoreSheet({super.key});

  @override
  State<ScoreSheet> createState() => _ScoreSheetState();
}

class _ScoreSheetState extends State<ScoreSheet> {
  // 第一轮20个靶位的控制器
  final List<TextEditingController> round1Controllers = List.generate(20, (_) => TextEditingController());
  // 第二轮20个靶位的控制器
  final List<TextEditingController> round2Controllers = List.generate(20, (_) => TextEditingController());

  String round1Result = '0';
  String round2Result = '0';
  String totalResult = '0';

  // 计算单轮总分
  int calculateRoundScore(List<TextEditingController> controllers) {
    return controllers.fold(0, (sum, controller) {
      return sum + (int.tryParse(controller.text) ?? 0);
    });
  }

  void calculateAllScores() {
    setState(() {
      final r1 = calculateRoundScore(round1Controllers);
      final r2 = calculateRoundScore(round2Controllers);
      round1Result = r1.toString();
      round2Result = r2.toString();
      totalResult = (r1 + r2).toString();
    });
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(
        children: [
          // 横向排列两轮计分区域
          Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              // 第一轮计分列
              Expanded(
                child: ScoreColumn(
                  roundName: '第一轮',
                  controllers: round1Controllers,
                ),
              ),
              const SizedBox(width: 16),
              // 第二轮计分列
              Expanded(
                child: ScoreColumn(
                  roundName: '第二轮',
                  controllers: round2Controllers,
                ),
              ),
            ],
          ),
          const SizedBox(height: 24),
          // 计算按钮
          ElevatedButton(
            onPressed: calculateAllScores,
            child: const Text('计算总分'),
          ),
          const SizedBox(height: 16),
          // 总分展示
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              Column(
                children: [
                  const Text('第一轮总分:', style: TextStyle(fontSize: 18)),
                  Text(round1Result, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
                ],
              ),
              Column(
                children: [
                  const Text('第二轮总分:', style: TextStyle(fontSize: 18)),
                  Text(round2Result, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
                ],
              ),
              Column(
                children: [
                  const Text('总合计:', style: TextStyle(fontSize: 18)),
                  Text(totalResult, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.red)),
                ],
              ),
            ],
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    // 销毁所有控制器,避免内存泄漏
    for (var controller in round1Controllers) {
      controller.dispose();
    }
    for (var controller in round2Controllers) {
      controller.dispose();
    }
    super.dispose();
  }
}

// 可复用的单轮计分列组件
class ScoreColumn extends StatelessWidget {
  final String roundName;
  final List<TextEditingController> controllers;

  const ScoreColumn({
    super.key,
    required this.roundName,
    required this.controllers,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(roundName, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
        const SizedBox(height: 8),
        // 生成20个靶位行
        ...List.generate(20, (index) {
          return Padding(
            padding: const EdgeInsets.symmetric(vertical: 4),
            child: Row(
              children: [
                SizedBox(
                  width: 80,
                  child: Text('Target ${index + 1}:'),
                ),
                Expanded(
                  child: TextField(
                    keyboardType: TextInputType.number,
                    controller: controllers[index],
                    textAlign: TextAlign.center,
                    decoration: const InputDecoration(
                      border: OutlineInputBorder(),
                      contentPadding: EdgeInsets.symmetric(vertical: 8),
                    ),
                  ),
                ),
              ],
            ),
          );
        }),
      ],
    );
  }
}

关键优化点说明

  • 组件复用:将单轮计分区域封装为ScoreColumn,避免重复代码,也方便后续扩展多轮需求
  • 控制器管理:用列表存储两轮的控制器,替代单个变量命名,更易维护
  • 布局结构:用Row包裹两个Expanded的ScoreColumn,保证两列平分宽度,避免布局溢出
  • 错误处理:使用int.tryParse替代int.parse,防止空输入导致的崩溃
  • 内存管理:在dispose方法中销毁所有控制器,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 21:57:00