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

Flutter蓝牙设备列表渲染错误求助:RenderFlex hasSize断言失败

问题分析

你的渲染错误核心原因是外层Column没有明确的高度约束,导致它的高度被评估为无限大,进而内部的Flexible和ListView无法正确计算布局空间,触发了无限高度的断言失败。从错误日志里的BoxConstraints(0.0<=w<=360.0, 0.0<=h<=Infinity)也能验证这一点——当前Column的高度没有上限。

解决方案

将整个页面结构包裹在Scaffold中,利用Scaffold的body提供屏幕级的高度约束;同时调整组件布局逻辑,确保内部元素能正确分配空间。

修改后的完整代码
import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

class BluetoothScreen extends StatefulWidget {
  @override
  _BluetoothScreenState createState() => _BluetoothScreenState();
}

class _BluetoothScreenState extends State<BluetoothScreen> {
  List<BluetoothDevice> devicesList = [];
  BluetoothDevice? connectedDevice;
  bool isScanning = false;

  @override
  void initState() {
    super.initState();
    scanForDevices();
  }

  void scanForDevices() async {
    setState(() {
      isScanning = true;
      devicesList.clear();
    });

    // 利用startScan的timeout自动停止扫描,无需额外延迟
    FlutterBluePlus.startScan(timeout: const Duration(seconds: 4));

    final subscription = FlutterBluePlus.scanResults.listen((results) {
      setState(() {
        devicesList = results.map((r) => r.device).toList();
      });
    });

    // 监听扫描状态,结束后取消订阅避免内存泄漏
    await FlutterBluePlus.isScanning.firstWhere((isScanning) => !isScanning);
    subscription.cancel();
    setState(() {
      isScanning = false;
    });
  }

  void connectToDevice(BluetoothDevice device) async {
    await device.connect();
    setState(() {
      connectedDevice = device;
    });
  }

  void disconnectFromDevice() async {
    if (connectedDevice != null) {
      await connectedDevice!.disconnect();
      setState(() {
        connectedDevice = null;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    // 用Scaffold作为页面根Widget,提供正确的布局约束
    return Scaffold(
      appBar: AppBar(title: const Text('蓝牙设备连接')),
      body: Column(
        children: <Widget>[
          // 用Expanded确保设备列表区域占据剩余可用高度
          Expanded(
            child: isScanning
                ? const Center(child: CircularProgressIndicator())
                : devicesList.isEmpty
                    ? const Center(child: Text('未找到设备'))
                    : ListView.builder(
                        itemCount: devicesList.length,
                        itemBuilder: (context, index) {
                          final device = devicesList[index];
                          return ListTile(
                            title: Text(device.name.isNotEmpty
                                ? device.name
                                : '无名称设备'),
                            subtitle: Text(device.id.toString()),
                            onTap: () {
                              connectToDevice(device);
                            },
                          );
                        },
                      ),
          ),
          if (connectedDevice != null)
            Padding(
              padding: const EdgeInsets.all(10.0),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text('已连接至 ${connectedDevice!.name}'),
                  ElevatedButton(
                    onPressed: disconnectFromDevice,
                    child: const Text('断开连接'),
                  ),
                ],
              ),
            ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: ElevatedButton(
              onPressed: scanForDevices,
              child: const Text('扫描设备'),
            ),
          ),
        ],
      ),
    );
  }
}
关键修改点
  • 用Scaffold作为页面根组件,通过它的body提供屏幕高度约束,彻底解决无限高度问题
  • 将外层的Flexible替换为Expanded,确保设备列表区域能占据屏幕剩余可用高度
  • 优化扫描逻辑:利用FlutterBluePlus.isScanning流监听扫描结束,取消订阅避免内存泄漏,同时去掉冗余的Future.delayed

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 12:14:51