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

Flutter使用screenshot库捕获组件时遇No MediaQuery祖先缺失错误

解决方案:解决screenshot库captureFromWidget的MediaQuery缺失问题

错误原因

你的Speedometer组件依赖MediaQuery.of(context)获取设备尺寸,但captureFromWidget是创建一个独立的Widget树进行捕获,这个树默认没有MediaQuery作为祖先节点,因此触发该错误。

有效修复方案

方案1:给捕获的Widget添加MediaQuery祖先

直接在要捕获的Widget外层包裹MediaQuery,手动指定所需的尺寸数据,无需依赖完整的MaterialApp:

await screenshotController
    .captureFromWidget(
  MediaQuery(
    data: MediaQueryData(
      size: Size(500, 300), // 对应外层Container的尺寸
      devicePixelRatio: MediaQuery.of(context).devicePixelRatio, // 复用当前设备的像素比
    ),
    child: Container(
      height: 300,
      width: 500,
      color: Colors.yellow,
      child: Speedometer(data: {"Working": 70, "Average": 10, "Bad": 20, "ItemName": ""}),
    ),
  ),
)
.then((Uint8List? value) async {
  speedometerDiagramBytes = value!;
});

方案2:用完整MaterialApp包裹(适合依赖Material组件的场景)

如果你的组件依赖Material风格的上下文,可包裹MaterialApp并指定必要参数(必须设置locale):

await screenshotController
    .captureFromWidget(
  MaterialApp(
    locale: Locale('en'), // MaterialApp必填参数
    home: Container(
      height: 300,
      width: 500,
      color: Colors.yellow,
      child: Speedometer(data: {"Working": 70, "Average": 10, "Bad": 20, "ItemName": ""}),
    ),
  ),
)
.then((Uint8List? value) async {
  speedometerDiagramBytes = value!;
});

方案3:重构Speedometer组件(彻底消除MediaQuery依赖)

修改组件,将设备判断结果和尺寸作为参数传入,避免在组件内部调用MediaQuery.of(context):

class Speedometer extends StatelessWidget {
  final Map<String, dynamic> data;
  final bool isLaptop;
  final bool isDesktop;

  Speedometer({required this.data, required this.isLaptop, required this.isDesktop});

  @override
  Widget build(BuildContext context) {
    double workingValue = data["Working"];
    double averageValue = data["Average"];
    double badValue = data["Bad"];
    String itemName = data["ItemName"];

    return Container(
      height: 100,
      width: 100,
      child: Center(
        child: Stack(
          children: [
            Align(
              alignment: Alignment.center,
              child: CustomPaint(
                size: isLaptop ? Size(450, 450) : Size(300, 400),
                painter: SpeedometerPainter(
                  workingValue: workingValue,
                  averageValue: averageValue,
                  badValue: badValue,
                  displayLabel: true
                ),
              ),
            ),
            Positioned(
              top: isLaptop ? 10 : 15,
              left: isLaptop ? 15 : 45,
              child: itemName == "Truck"
                  ? Image.asset(truckIcon, height: isDesktop ? 40 : 30, width: isDesktop ? 40 : 30, fit: BoxFit.contain)
                  : Image.asset(excavatorIcon, height: isDesktop ? 40 : 30, width: isDesktop ? 40 : 30, fit: BoxFit.contain)
            )
          ],
        ),
      ),
    );
  }
}

调用时在原有上下文(已包含MediaQuery)中获取设备参数,再传入组件:

// 在有MediaQuery的页面上下文里先获取设备状态
final isLaptop = checkIfLaptop;
final isDesktop = checkIfDesktop;

await screenshotController
    .captureFromWidget(
  Container(
    height: 300,
    width: 500,
    color: Colors.yellow,
    child: Speedometer(
      data: {"Working": 70, "Average": 10, "Bad": 20, "ItemName": ""},
      isLaptop: isLaptop,
      isDesktop: isDesktop,
    ),
  ),
)
.then((Uint8List? value) async {
  speedometerDiagramBytes = value!;
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 11:30:10