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

Flutter中flutter_svg网络SVG渲染异常的自定义错误处理方案

解决SvgPicture无errorBuilder的异常处理问题

针对网络SVG包含禁用标签导致的渲染异常,你可以通过以下几种方式实现类似Image.asset的错误处理逻辑:

1. 自定义带错误捕获的SVG组件(推荐)

通过手动发起网络请求并解析SVG,用try-catch捕获所有异常(包括网络错误、解析错误),然后返回自定义的错误组件:

import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:http/http.dart' as http;

class SafeNetworkSvg extends StatefulWidget {
  final String svgUrl;
  final Widget errorWidget;
  final Widget loadingWidget;
  final BoxFit fit;

  const SafeNetworkSvg({
    super.key,
    required this.svgUrl,
    this.errorWidget = const Icon(Icons.broken_image, color: Colors.grey),
    this.loadingWidget = const CircularProgressIndicator.adaptive(),
    this.fit = BoxFit.contain,
  });

  @override
  State<SafeNetworkSvg> createState() => _SafeNetworkSvgState();
}

class _SafeNetworkSvgState extends State<SafeNetworkSvg> {
  late Future<DrawableRoot?> _svgParseFuture;

  @override
  void initState() {
    super.initState();
    _svgParseFuture = _fetchAndParseSvg();
  }

  Future<DrawableRoot?> _fetchAndParseSvg() async {
    try {
      // 发起网络请求获取SVG内容
      final response = await http.get(Uri.parse(widget.svgUrl));
      if (response.statusCode != 200) throw Exception('网络请求失败');

      // 手动解析SVG,捕获解析异常
      final parser = SvgParser();
      return await parser.parse(response.body);
    } catch (e) {
      debugPrint('SVG加载/解析失败: $e');
      return null;
    }
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<DrawableRoot?>(
      future: _svgParseFuture,
      builder: (context, snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.waiting:
            return widget.loadingWidget;
          default:
            if (snapshot.hasData && snapshot.data != null) {
              return SvgPicture.fromDrawableRoot(
                snapshot.data!,
                fit: widget.fit,
              );
            } else {
              return widget.errorWidget;
            }
        }
      },
    );
  }
}

使用方式:

SafeNetworkSvg(
  svgUrl: 'https://example.com/your.svg',
  errorWidget: Text('SVG加载失败'),
)

2. 全局错误拦截(不推荐,影响范围广)

如果不想自定义组件,可以通过全局ErrorWidget.builder拦截SVG解析异常,统一返回错误组件:

void main() {
  ErrorWidget.builder = (FlutterErrorDetails details) {
    // 判断是否为SVG解析异常
    if (details.exception is SvgParserException) {
      return const Center(child: Icon(Icons.broken_image));
    }
    // 其他异常保持默认处理
    return ErrorWidget(details.exception);
  };
  runApp(const MyApp());
}

这种方式会拦截所有页面中出现的SVG解析错误,适合需要全局统一错误样式的场景,但灵活性差,无法针对单个SVG组件自定义错误UI。

3. 结合FutureBuilder与try-catch的简化方案

如果不想写复杂的自定义组件,也可以在FutureBuilder中手动处理解析逻辑:

FutureBuilder(
  future: _loadSvg('https://example.com/your.svg'),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return const CircularProgressIndicator();
    }
    if (snapshot.hasError || snapshot.data == null) {
      return const Icon(Icons.error);
    }
    return SvgPicture.string(snapshot.data!);
  },
)

// 单独的加载解析方法
Future<String?> _loadSvg(String url) async {
  try {
    final response = await http.get(Uri.parse(url));
    if (response.statusCode != 200) return null;
    // 提前解析一次,捕获错误
    await SvgParser().parse(response.body);
    return response.body;
  } catch (e) {
    debugPrint('SVG错误: $e');
    return null;
  }
}

这个方案通过提前解析SVG捕获异常,避免直接使用SvgPicture.string时崩溃,适合简单场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 10:42:36