Flutter中TextField不显示,出现RenderBox无尺寸点击测试错误
问题
开发一款沉浸式闹钟Flutter应用,用户需完成答题任务才能关闭闹钟。使用TextField实现答题输入时,触发Cannot hit test a render box with no size错误,且TextField无法正常显示。
错误信息:
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 { // ignore: avoid_print print("alarm is playing"); 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(), ), ); }, //on pressed child: const Text( "Tasks page", style: TextStyle(color: Colors.white), ), ) ], ), ), ), ); } //widget build } 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 United States of America?", style: TextStyle( backgroundColor: Colors.white, color: Colors.black, fontSize: 30.0, ), ), Expanded( child: TextField( controller: _textcontroller, decoration: InputDecoration( hintText: "Type your answer here!", border: const OutlineInputBorder(), suffixIcon: IconButton( onPressed: () { _textcontroller.clear(); }, icon: const Icon(Icons.clear), ), ), ), ), ], ), ), ), ), ); } //widget build } 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, ), ), Expanded( child: TextField( controller: _textcontroller2, decoration: InputDecoration( hintText: "Type your answer here!", border: const OutlineInputBorder(), suffixIcon: IconButton( onPressed: () { _textcontroller2.clear(); }, icon: const Icon(Icons.clear), ), ), ), ), ], ), ), ), ), ); } //widget build } 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, ), ), Expanded( child: TextField( controller: _textcontroller3, decoration: InputDecoration( hintText: "Type your answer here!", border: const OutlineInputBorder(), suffixIcon: IconButton( onPressed: () { _textcontroller3.clear(); }, icon: const Icon(Icons.clear), ), ), ), ), ], ), ), ), ), ); } //widget build } 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, ), ), Expanded( child: TextField( controller: _textcontroller4, decoration: InputDecoration( hintText: "Type your answer here!", border: const OutlineInputBorder(), suffixIcon: IconButton( onPressed: () { _textcontroller4.clear(); }, icon: const Icon(Icons.clear), ), ), ), ), ], ), ), ), ), ); } //widget build } class Congrats extends StatefulWidget { const Congrats({super.key}); @override State<Congrats> createState() => _Congrats(); } class _Congrats extends State<Congrats> { @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) // ignore: avoid_print print("Alarm has stoped"); }, backgroundColor: Colors.red, child: const Text("Home"), ), body: Padding( padding: const EdgeInsets.all(8.0), child: Center( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: const [ Expanded( child: 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, ), ), ), ], ), ), ), ), ); } //widget build }
解决方案
问题根源
- 重复嵌套MaterialApp:每个页面都重新创建MaterialApp,导致上下文混乱,布局计算异常。Flutter应用仅需一个根MaterialApp。
- Row布局约束冲突:长文本未开启自动换行,且Row中TextField的空间分配不合理,导致RenderBox无法计算有效尺寸。
- 音频API弃用:使用了已弃用的
AudioCache,存在潜在资源加载问题。
修复步骤
- 移除页面中的MaterialApp:仅保留根
MyApp中的MaterialApp,其他页面直接返回Scaffold。 - 优化文本与TextField布局:
- 给文本添加
Flexible并开启softWrap: true,实现自动换行避免溢出。 - 将Row布局改为Column,让文本和TextField垂直排列,适配小屏幕。
- 给TextField设置固定宽度(基于屏幕宽度比例),确保尺寸明确。
- 给文本添加
- 替换音频API:使用
AudioPlayer直接加载资源,同时添加资源释放逻辑避免内存泄漏。
修改后完整代码
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> { AudioPlayer? _audioPlayer; @override void dispose() { _audioPlayer?.dispose(); super.dispose(); } @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 { print("alarm is playing"); _audioPlayer = AudioPlayer(); await _audioPlayer?.play(AssetSource('musicForapp.mp3')); }, backgroundColor: Colors.red, child: const Icon(Icons.punch_clock), ), body: Padding( padding: const EdgeInsets.all(20.0), 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: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Flexible( child: Text( "How many states are there in the United States of America?", style: TextStyle( backgroundColor: Colors.white, color: Colors.black, fontSize: 24.0, ), textAlign: TextAlign.center, softWrap: true, ), ), const SizedBox(height: 20), SizedBox( width: MediaQuery.of(context).size.width * 0.8, child: TextField( controller: _textcontroller, decoration: InputDecoration( hintText: "Type your answer here!", border: const OutlineInputBorder(), suffixIcon: IconButton( onPressed: () { _textcontroller.clear(); },
相关产品推荐
相关产品推荐

