如何修复ListTile触发RenderBox was not laid out布局异常问题
问题原因
- 布局错误的根源是
Row的子元素没有明确横向宽度约束:ListTile默认会填充父组件提供的最大横向宽度,你直接将返回ListTile的StreamBuilder放在Row的children列表中时,Row默认不会给子元素限制横向尺寸,导致ListTile布局时计算出无限宽度,最终触发hasSize断言失败。
解决方法
- 你只需要用
Expanded直接包裹整个StreamBuilder即可。Expanded会强制其子组件在Row的横向主轴上填充剩余可用空间,给ListTile明确的宽度约束,即可解决布局异常。如果你的Row后续要添加其他横向排列的组件,Expanded也会自动计算剩余宽度分配给ListTile,不需要额外调整。
修改后的代码示例:
Row get upperSection { return Row( children: <Widget>[ // 用Expanded包裹整个StreamBuilder Expanded( child: StreamBuilder<BluetoothDeviceState>( stream: widget.device.state, initialData: BluetoothDeviceState.connecting, builder: (c, snapshot) => ListTile( leading: (snapshot.data == BluetoothDeviceState.connected) ? const Icon(Icons.bluetooth_connected) : const Icon(Icons.bluetooth_disabled), title: Text('Device is ${snapshot.data.toString().split('.')[0]}.'), subtitle: Text('${widget.device.id}'), trailing: StreamBuilder<bool>( //The below stream is to show either a refresh button or //CircularProgress based on the service discovering status, //and a IndexedStack widget is used to present the needed widget stream: widget.device.isDiscoveringServices, initialData: false, builder: (c, snapshot) => IndexedStack( index: snapshot.data ? 0 : 0, children: <Widget>[ IconButton( icon: const Icon(Icons.refresh), onPressed: () => widget.device.discoverServices(), ), const IconButton( icon: SizedBox( child: CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(Colors.grey), ), width: 17.0, height: 17.0, ), onPressed: null, ), ], ), ), ), ), ), ], ); }
内容的提问来源于stack exchange,提问作者Ahmad Zaklouta
相关产品推荐
相关产品推荐

