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

Flutter开发:使用TextField触发RenderBox无尺寸命中测试错误

问题

我正在开发一款沉浸式闹钟Flutter应用,用户需完成答题任务才能关闭闹钟,以此刺激大脑辅助清醒。在使用TextField实现答案输入功能时,调试代码跳转到box.dart文件,触发如下错误:

throw FlutterError.fromParts(<DiagnosticsNode>[
          ErrorSummary('Cannot hit test a render box with no size.'),
          describeForError('The hitTest() method was called on this RenderBox'),
          ErrorDescription(
            'Although this node is not marked as needing layout, '
            'its size is not set.',
          ),
          ErrorHint(
            'A RenderBox object must have an '
            'explicit size before it can be hit-tested. Make sure '
            'that the RenderBox in question sets its size during layout.',
          ),
        ]);
      }

以下是我的完整代码:

import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';
//import 'package:audioplayers/audio_cache.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Time Attack',
      theme: ThemeData(
        primarySwatch: Colors.red,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.black,
        appBar: AppBar(
          backgroundColor: Colors.red,
          title: const Text('Time Attack'),
          centerTitle: true,
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () async {
            final player = AudioCache();
            //bool isPLaying = false;
            await player.load('musicForapp.mp3');
            AudioPlayer p = AudioPlayer();
            p.audioCache = player;
            await p.play(AssetSource('musicForapp.mp3'));
          },
          backgroundColor: Colors.red,
          child: const Icon(Icons.punch_clock),
        ),
        body: Padding(
          padding: const EdgeInsets.all(170),
          child: Column(
            children: [
              const Text(
                "Click the Icon in the bottem right to simulate alarm",
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 30.0,
                ),
              ),
              ElevatedButton(
                style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
                onPressed: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (_) => const TasksPage(),
                    ),
                  );
                },
                child: const Text(
                  "Tasks page",
                  style: TextStyle(color: Colors.white),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

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

  @override
  State<TasksPage> createState() => _TasksPageState();
}

class _TasksPageState extends State<TasksPage> {
  final _textcontroller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.black,
        appBar: AppBar(
          backgroundColor: Colors.red,
          title: const Text('Tasks'),
          centerTitle: true,
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (_) => const SecondTask(),
              ),
            );
          },
          backgroundColor: Colors.red,
          child: const Text("Next"),
        ),
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Center(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                const Text(
                  "How many states are there in the Uninted States of America?",
                  style: TextStyle(
                    backgroundColor: Colors.white,
                    color: Colors.black,
                    fontSize: 30.0,
                  ),
                ),
                TextField(
                  controller: _textcontroller,
                  decoration: InputDecoration(
                    hintText: "Type your answer here!",
                    border: const OutlineInputBorder(),
                    suffixIcon: IconButton(
                      onPressed: () {
                        _textcontroller.clear();
                      },
                      icon: const Icon(Icons.clear),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

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

  @override
  State<SecondTask> createState() => _SecondTask();
}

class _SecondTask extends State<SecondTask> {
  final _textcontroller2 = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.black,
        appBar: AppBar(
          backgroundColor: Colors.red,
          title: const Text('Tasks'),
          centerTitle: true,
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (_) => const Thirdtask(),
              ),
            );
          },
          backgroundColor: Colors.red,
          child: const Text("Next"),
        ),
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Center(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                const Text(
                  "how many oceans are there?",
                  style: TextStyle(
                    backgroundColor: Colors.white,
                    color: Colors.black,
                    fontSize: 30.0,
                  ),
                ),
                TextField(
                  controller: _textcontroller2,
                  decoration: InputDecoration(
                    hintText: "Type your answer here!",
                    border: const OutlineInputBorder(),
                    suffixIcon: IconButton(
                      onPressed: () {
                        _textcontroller2.clear();
                      },
                      icon: const Icon(Icons.clear),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

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

  @override
  State<Thirdtask> createState() => _Thirdtask();
}

class _Thirdtask extends State<Thirdtask> {
  final _textcontroller3 = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.black,
        appBar: AppBar(
          backgroundColor: Colors.red,
          title: const Text('Tasks'),
          centerTitle: true,
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (_) => const Finaltask(),
              ),
            );
          },
          backgroundColor: Colors.red,
          child: const Text("Next"),
        ),
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Center(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                const Text(
                  "What is 8 x 7?",
                  style: TextStyle(
                    backgroundColor: Colors.white,
                    color: Colors.black,
                    fontSize: 30.0,
                  ),
                ),
                TextField(
                  controller: _textcontroller3,
                  decoration: InputDecoration(
                    hintText: "Type your answer here!",
                    border: const OutlineInputBorder(),
                    suffixIcon: IconButton(
                      onPressed: () {
                        _textcontroller3.clear();
                      },
                      icon: const Icon(Icons.clear),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

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

  @override
  State<Finaltask> createState() => _Finaltask();
}

class _Finaltask extends State<Finaltask> {
  final _textcontroller4 = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.black,
        appBar: AppBar(
          backgroundColor: Colors.red,
          title: const Text('Tasks'),
          centerTitle: true,
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (_) => const Congrats(),
              ),
            );
          },
          backgroundColor: Colors.red,
          child: const Text("Submit"),
        ),
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Center(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                const Text(
                  "Riddle: What goes up but never comes back down?",
                  style: TextStyle(
                    backgroundColor: Colors.white,
                    color: Colors.black,
                    fontSize: 30.0,
                  ),
                ),
                TextField(
                  controller: _textcontroller4,
                  decoration: InputDecoration(
                    hintText: "Type your answer here!",
                    border: const OutlineInputBorder(),
                    suffixIcon: IconButton(
                      onPressed: () {
                        _textcontroller4.clear();
                      },
                      icon: const Icon(Icons.clear),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

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

  @override
  State<Congrats> createState() => _Congrats();
}

class _Congrats extends State<Congrats> {
  final _textcontroller4 = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Colors.black,
        appBar: AppBar(
          backgroundColor: Colors.red,
          title: const Text('Good Job!'),
          centerTitle: true,
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (_) => const MyHomePage(),
              ),
            );
            //player.clear('explosion.mp3');  (to stop alarm)
          },
          backgroundColor: Colors.red,
          child: const Text("Home"),
        ),
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Center(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: const [
                Text(
                  "Congratulations you completed your tasks, Click the home button to return home and stop the timer!",
                  style: TextStyle(
                    backgroundColor: Colors.white,
                    color: Colors.black,
                    fontSize: 30.0,
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

问题分析与解决方案

错误根源

  1. 重复实例化MaterialApp:每个页面都创建了新的MaterialApp,破坏Flutter上下文层级,导致布局渲染异常。Flutter应用仅需一个根MaterialApp。
  2. Row布局中TextField无宽度约束:Row组件内的TextField无法自动确定自身尺寸,触发无尺寸渲染错误。
  3. 长文本未做换行处理:部分题目文本过长,在Row中挤压TextField空间,加剧布局冲突。

修复方案

  1. 移除页面中的MaterialApp:所有子页面直接返回Scaffold,保留根MyApp中的MaterialApp作为全局配置。
  2. 给TextField添加宽度约束:用SizedBox指定TextField宽度,或通过Expanded分配布局空间。
  3. 优化文本布局:将长文本放入Expanded组件,允许自动换行,避免挤压其他元素。

修改后的完整代码

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Time Attack',
      theme: ThemeData(
        primarySwatch: Colors.red,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      appBar: AppBar(
        backgroundColor: Colors.red,
        title: const Text('Time Attack'),
        centerTitle: true,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final player = AudioCache();
          await player.load('musicForapp.mp3');
          AudioPlayer p = AudioPlayer();
          p.audioCache = player;
          await p.play(AssetSource('musicForapp.mp3'));
        },
        backgroundColor: Colors.red,
        child: const Icon(Icons.punch_clock),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              "Click the Icon in the bottom right to simulate alarm",
              style: TextStyle(
                color: Colors.white,
                fontSize: 20.0,
              ),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 30),
            ElevatedButton(
              style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (_) => const TasksPage(),
                  ),
                );
              },
              child: const Text(
                "Tasks page",
                style: TextStyle(color: Colors.white),
              ),
            )
          ],
        ),
      ),
    );
  }
}

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

  @override
  State<TasksPage> createState() => _TasksPageState();
}

class _TasksPageState extends State<TasksPage> {
  final _textcontroller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      appBar: AppBar(
        backgroundColor: Colors.red,
        title: const Text('Tasks'),
        centerTitle: true,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (_) => const SecondTask(),
            ),
          );
        },
        backgroundColor: Colors.red,
        child: const Text("Next"),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Center(
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Expanded(
                child: const Text(
                  "How many states are there in the United States of America?",
                  style: TextStyle(
                    backgroundColor: Colors.white,
                    color: Colors.black,
                    fontSize: 20.0,
                  ),
                  textAlign: TextAlign.center,
                ),
              ),
              const SizedBox(width: 10),
              SizedBox(
                width: 150,
                child: TextField(
                  controller: _textcontroller,
                  decoration: InputDecoration(
                    hintText: "Type your answer here!",
                    border: const OutlineInputBorder(),
                    suffixIcon: IconButton(
                      onPressed: () {
                        _textcontroller.clear();
                      },
                      icon: const Icon(Icons.clear),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

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

  @override
  State<SecondTask> createState() => _SecondTask();
}

class _SecondTask extends State<SecondTask> {
  final _textcontroller2 = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      appBar: AppBar(
        backgroundColor: Colors.red,
        title: const Text('Tasks'),
        center
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 07:45:34