Flutter中Row/Column结合Expanded和FittedBox布局异常求助
Flutter布局异常排查与修复
需求
- 用Row实现左右布局:左侧显示日期+时间(单列展示,通过FittedBox适配不同设备字体大小),右侧展示最大化网络图片
- 左侧用Expanded组件,右侧Expanded的flex设为2
报错信息
调度器库异常
══╡ EXCEPTION CAUGHT BY SCHEDULER LIBRARY ╞═════════════════════════════════════════════════════════ The following assertion was thrown during a scheduler callback: 'package:flutter/src/widgets/binding.dart': Failed assertion: line 849 pos 12: '!debugBuildingDirtyElements': is not true. Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause. In either case, please report this assertion by filing a bug on GitHub: https://github.com/flutter/flutter/issues/new?template=2_bug.md When the exception was thrown, this was the stack: #2 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:849:12) #3 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:378:5) #4 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1175:15) #5 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1104:9) #6 SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:881:7) (elided 6 frames from class _AssertionError, class _RawReceivePortImpl, class _Timer, and dart:async-patch) ════════════════════════════════════════════════════════════════════════════════════════════════════ Performing hot reload... Reloaded 0 libraries in 31ms (compile: 7 ms, reload: 0 ms, reassemble: 13 ms). Another exception was thrown: 'package:flutter/src/widgets/binding.dart': Failed assertion: line 849 pos 12: '!debugBuildingDirtyElements': is not true. Another exception was thrown: 'package:flutter/src/widgets/binding.dart': Failed assertion: line 849 pos 12: '!debugBuildingDirtyElements': is not true.
布局未完成错误
The following RenderObject was being processed when the exception was fired: RenderFittedBox#e50d7 relayoutBoundary=up15 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE: creator: FittedBox ← Column ← Stack ← IntrinsicWidth ← Padding ← SizedBox ← Row ← MediaQuery ← Padding ← SafeArea ← Align ← ColoredBox ← ⋯ parentData: offset=Offset(0.0, 0.0); flex=null; fit=null (can use size) constraints: BoxConstraints(w=237.2, 0.0<=h<=Infinity) size: MISSING fit: fitWidth alignment: Alignment.center textDirection: ltr This RenderObject had the following descendants (showing up to depth 5): child: RenderParagraph#39ce4 relayoutBoundary=up16 NEEDS-PAINT text: TextSpan ════════════════════════════════════════════════════════════════════════════════════════════════════ Another exception was thrown: RenderBox was not laid out: RenderFittedBox#e50d7 relayoutBoundary=up15 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE Another exception was thrown: RenderBox was not laid out: RenderFlex#e77d9 relayoutBoundary=up14 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
当前代码
Widget build(BuildContext context) { return Scaffold( body: Container( alignment: Alignment.center, color: Color.fromRGBO(0, 0, 0, 1), child: SafeArea( child: Row( children: [ Expanded( child: Padding( padding: const EdgeInsets.all(8.0), child: IntrinsicWidth( child: Stack( children: [ Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ FittedBox( fit: BoxFit.fitWidth, child: Text( _localeDate, style: TextStyle( color: Colors.white, ), ), ), SizedBox( height: 20, ), FittedBox( fit: BoxFit.fitWidth, child: Text( _time, style: TextStyle( color: Colors.white, ), ), ), ], ), ], ), ), ), ), Expanded( flex: 2, child: Image(fit: BoxFit.cover, image: NetworkImage(img))) ], ), ), ), ); }
修复方案
问题根源
- 冗余组件:
Stack和IntrinsicWidth属于无意义嵌套,IntrinsicWidth强制子组件根据自身内容计算宽度,与FittedBox.fitWidth的约束逻辑冲突,导致RenderFittedBox无法获取有效尺寸。 - 约束冲突:
Column未明确高度约束,配合无限高度的父容器,触发布局计算死循环。
修复后代码
Widget build(BuildContext context) { return Scaffold( body: Container( color: Color.fromRGBO(0, 0, 0, 1), child: SafeArea( child: Row( children: [ // 左侧日期时间区域 Expanded( child: Padding( padding: const EdgeInsets.all(8.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, // 保证文字左对齐、单列展示 children: [ FittedBox( fit: BoxFit.scaleDown, // 容器不足时缩小文字,足够时保留原尺寸 child: Text( _localeDate, style: TextStyle(color: Colors.white), ), ), SizedBox(height: 20), FittedBox( fit: BoxFit.scaleDown, child: Text( _time, style: TextStyle(color: Colors.white), ), ), ], ), ), ), // 右侧图片区域 Expanded( flex: 2, child: Image( fit: BoxFit.cover, height: double.infinity, // 强制占满父容器高度,实现最大化展示 image: NetworkImage(img), ), ), ], ), ), ), ); }
关键修改点
- 移除
Stack和IntrinsicWidth,简化布局层级,让约束正常传递。 - 将
FittedBox的fit改为BoxFit.scaleDown:容器宽度足够时保留原字体大小,不足时自动缩小,更适配单列文字场景。 - 给右侧
Image添加height: double.infinity,确保图片占满Row的高度,实现最大化展示。 - 设置
Column的crossAxisAlignment: CrossAxisAlignment.start,保证日期和时间文字左对齐,维持单列布局。
内容的提问来源于stack exchange,提问作者Tdayo
相关产品推荐
相关产品推荐

