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

Flutter中Row嵌套Column内ListView.Builder布局报错求助

解决Flutter飞镖游戏计算器双列布局的RenderBox未布局问题

错误原因

把包含ListView的Column嵌套到Row中时,Row不会给子Column提供明确的垂直约束,而Column默认会自适应子组件高度。ListView在shrinkWrap: true下虽会根据内容收缩,但缺少外部高度限制时,布局系统无法计算其最终尺寸,从而抛出RenderBox was not laid out错误。

修复方案

通过两步调整布局约束即可解决:

  • 给Row中的每个Column包裹Expanded,让它们平分Row的水平空间,同时继承父容器的垂直高度约束
  • 在Column内部,用Expanded包裹ListView,让它占据Column内除标题、剩余分数外的所有垂直空间

修改后的完整代码

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const GamePage(),
    );
  }
}

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

  @override
  State<GamePage> createState() => _GamePageState();
}

class _GamePageState extends State<GamePage> {
  List<String> thrownScoresOne = [];
  List<String> thrownScoresTwo = [];
  int playerOne501 = 501;
  int playerTwo501 = 501;
  final TextEditingController _playerOneScoreController =
      TextEditingController();
  final TextEditingController _playerTwoScoreController =
      TextEditingController();

  @override
  void dispose() {
    _playerOneScoreController.dispose();
    _playerTwoScoreController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("飞镖游戏计算器"),
      ),
      body: SafeArea(
        child: Container(
          padding: const EdgeInsets.symmetric(horizontal: 32),
          width: double.infinity,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              // 玩家一列,用Expanded约束宽度和高度
              Expanded(
                child: Column(
                  children: [
                    const Text("玩家一"),
                    Text(playerOne501.toString()),
                    // 用Expanded让ListView占据剩余垂直空间
                    Expanded(
                      child: ListView.builder(
                          shrinkWrap: true,
                          itemCount: thrownScoresOne.length,
                          itemBuilder: (BuildContext context, int index) {
                            return Padding(
                              padding: const EdgeInsets.symmetric(vertical: 4),
                              child: Text(thrownScoresOne[index]),
                            );
                          }),
                    ),
                    // TextField放在Column底部
                    Container(
                      margin: const EdgeInsets.only(bottom: 16),
                      child: TextField(
                        controller: _playerOneScoreController,
                        decoration: InputDecoration(
                          hintText: "输入得分",
                          border: OutlineInputBorder(
                              borderSide: Divider.createBorderSide(context)),
                          focusedBorder: OutlineInputBorder(
                              borderSide: Divider.createBorderSide(context)),
                          enabledBorder: OutlineInputBorder(
                              borderSide: Divider.createBorderSide(context)),
                          filled: true,
                          contentPadding: const EdgeInsets.all(8),
                        ),
                        onSubmitted: (text) {
                          thrownScoresOne.add(text);
                          // 可选:更新剩余分数逻辑
                          if (int.tryParse(text) != null) {
                            setState(() {
                              playerOne501 -= int.parse(text);
                            });
                          }
                          _playerOneScoreController.clear();
                          setState(() {});
                        },
                      ),
                    ),
                  ],
                ),
              ),
              // 玩家二列,同玩家一的布局约束
              Expanded(
                child: Column(
                  children: [
                    const Text("玩家二"),
                    Text(playerTwo501.toString()),
                    Expanded(
                      child: ListView.builder(
                          shrinkWrap: true,
                          itemCount: thrownScoresTwo.length,
                          itemBuilder: (BuildContext context, int index) {
                            return Padding(
                              padding: const EdgeInsets.symmetric(vertical: 4),
                              child: Text(thrownScoresTwo[index]),
                            );
                          }),
                    ),
                    Container(
                      margin: const EdgeInsets.only(bottom: 16),
                      child: TextField(
                        controller: _playerTwoScoreController,
                        decoration: InputDecoration(
                          hintText: "输入得分",
                          border: OutlineInputBorder(
                              borderSide: Divider.createBorderSide(context)),
                          focusedBorder: OutlineInputBorder(
                              borderSide: Divider.createBorderSide(context)),
                          enabledBorder: OutlineInputBorder(
                              borderSide: Divider.createBorderSide(context)),
                          filled: true,
                          contentPadding: const EdgeInsets.all(8),
                        ),
                        onSubmitted: (text) {
                          thrownScoresTwo.add(text);
                          // 可选:更新剩余分数逻辑
                          if (int.tryParse(text) != null) {
                            setState(() {
                              playerTwo501 -= int.parse(text);
                            });
                          }
                          _playerTwoScoreController.clear();
                          setState(() {});
                        },
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

额外优化点

  • 给ListView的每个item添加Padding,提升视觉体验
  • 增加分数合法性判断,避免非数字输入导致崩溃
  • 给TextField添加底部margin,避免被屏幕底部遮挡

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 07:30:52