Flutter HTML内容渲染插件flutter_html的使用

Flutter HTML内容渲染插件flutter_html的使用

安装

在你的 pubspec.yaml 文件中添加以下依赖:

dependencies:
  flutter_html: ^2.2.1

目前支持的HTML标签

目前flutter_html支持以下HTML标签:

标签 描述
<a> 超链接
<abbr> 缩写词
<acronym> 首字母缩略词
<address> 联系信息
<article> 独立的内容
<aside> 侧边栏内容
<audio> 音频
<b> 粗体文本
<bdi> 隔离文本方向
<bdo> 文本方向覆盖
<big> 大字体

目前支持的CSS属性

目前flutter_html支持以下CSS属性:

属性 描述
background-color 背景颜色
color 文本颜色
direction 文本方向
display 显示类型
font-family 字体系列
font-feature-settings 字体特征设置
font-size 字体大小

目前支持的内联CSS属性

目前flutter_html支持以下内联CSS属性:

属性 描述
background-color 背景颜色
border 边框
color 文本颜色
direction 文本方向
display 显示类型
font-family 字体系列
font-size 字体大小

为什么选择这个包?

这个包的设计初衷是为了简化HTML内容到Flutter控件树的渲染。它不仅支持基本样式,还提供了可选的自定义API来实现对控件渲染的精细控制。

API 参考

对于完整的API参考,请参阅 这里

构造函数

该包当前有两个不同的构造函数:Html()Html.fromDom()

  • Html() 构造函数适用于直接从源传递HTML数据。
  • Html.fromDom() 构造函数允许你在渲染之前修改或清理HTML数据。

参数

以下是 Html 小部件接受的主要参数及其描述:

Widget html = Html(
  data: htmlData, // HTML数据字符串
  onLinkTap: (String? url, RenderContext context, Map<String, String> attributes, dom.Element? element) {
    // 打开URL的逻辑
  },
  customRender: {
    "table": (context, child) {
      return SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        child: (context.tree as TableLayoutElement).toWidget(context),
      );
    }
  },
  onImageError: (Exception exception, StackTrace stackTrace) {
    // 图像加载错误的处理逻辑
  },
  onImageTap: (String? url, RenderContext context, Map<String, String> attributes, dom.Element? element) {
    // 图像点击的处理逻辑
  },
  tagsList: Html.tags..addAll(["bird", "flutter"]), // 要渲染的HTML标签列表
  style: {
    "table": Style(backgroundColor: Color.fromARGB(0x50, 0xee, 0xee, 0xee)),
    "tr": Style(border: Border(bottom: BorderSide(color: Colors.grey))),
    "th": Style(padding: EdgeInsets.all(6), backgroundColor: Colors.grey),
    "td": Style(padding: EdgeInsets.all(6), alignment: Alignment.topLeft),
    "h1": Style(color: Colors.red),
  },
  customImageRender: {
    networkSourceMatcher(domains: ["flutter.dev"]): (context, attributes, element) {
      return FlutterLogo(size: 36);
    },
    networkSourceMatcher(domains: ["mydomain.com"]): networkImageRender(
      headers: {"Custom-Header": "some-value"},
      altWidget: (alt) => Text(alt ?? ""),
      loadingWidget: () => Text("Loading..."),
    ),
    (attr, _) => attr["src"] != null && attr["src"]!.startsWith("/wiki"):
      networkImageRender(mapUrl: (url) => "https://upload.wikimedia.org" + url!),
    networkSourceMatcher(): networkImageRender(altWidget: (_) => FlutterLogo()),
  },
);

示例代码

下面是一个完整的示例代码,展示了如何使用 flutter_html 渲染复杂的HTML内容:

import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.deepPurple),
      home: MyHomePage(title: 'flutter_html Example'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

const htmlData = r"""
<p id='top'><a href='#bottom'>Scroll to bottom</a></p>
<h1>Header 1</h1>
<h2>Header 2</h2>
<h3>Header 3</h3>
<h4>Header 4</h4>
<h5>Header 5</h5>
<h6>Header 6</h6>
<h3>Ruby Support:</h3>
<p>
  <ruby>
    漢<rt>かん</rt>
    字<rt>じ</rt>
  </ruby>
  is Japanese Kanji.
</p>
<h3>Support for maxLines:</h3>
<h5>Lorem ipsum dolor sit amet, consectetur adipiscing elit...</h5>
<h3>Support for <code>sub</code>/<code>sup</code></h3>
Solve for <var>x<sub>n</sub></var>: log<sub>2</sub>(<var>x</var><sup>2</sup>+<var>n</var>) = 9<sup>3</sup>
<p>One of the most <span>common</span> equations in all of physics is <var>E</var>=<var>m</var><var>c</var><sup>2</sup>.</p>
<h3>Inline Styles:</h3>
<p>The should be <span style='color: blue;'>BLUE</span></p>
<p>The should be <span style='color: red;'>RED</span></p>
<p>The should be <span style='color: rgba(0, 0, 0, 0.10);'>BLACK with 10% alpha</span></p>
<p>The should be <span style='color: rgb(0, 97, 0);'>GREEN</span></p>
<p>The should be <span style='background-color: red; color: rgb(0, 97, 0);'>GREEN</span></p>
<p style="text-align: center;"><span style="color: rgba(0, 0, 0, 0.95);">blasdafjklasdlkjfkl</span></p>
<p style="text-align: right;"><span style="color: rgba(0, 0, 0, 0.95);">blasdafjklasdlkjfkl</span></p>
<p style="text-align: justify;"><span style="color: rgba(0, 0, 0, 0.95);">blasdafjklasdlkjfkl</span></p>
<p style="text-align: center;"><span style="color: rgba(0, 0, 0, 0.95);">blasdafjklasdlkjfkl</span></p>
<h3>Table support (with custom styling!):</h3>
<p><q>Famous quote...</q></p>
<table>
<colgroup>
  <col width="50%" />
  <col span="2" width="25%" />
</colgroup>
<thead>
<tr><th>One</th><th>Two</th><th>Three</th></tr>
</thead>
<tbody>
<tr>
  <td rowspan='2'>Rowspan\nRowspan\nRowspan\nRowspan\nRowspan\nRowspan\nRowspan\nRowspan\nRowspan\nRowspan</td><td>Data</td><td>Data</td>
</tr>
<tr>
  <td colspan="2"><img alt='Google' src='https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png' /></td>
</tr>
</tbody>
<tfoot>
<tr><td>fData</td><td>fData</td><td>fData</td></tr>
</tfoot>
</table>
<h3>Custom Element Support (inline: <bird></bird> and as block):</h3>
<flutter></flutter>
<flutter horizontal></flutter>
<h3 id='middle'>SVG support:</h3>
<svg id='svg1' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'>
  <circle r="32" cx="35" cy="65" fill="#F00" opacity="0.5"/>
  <circle r="32" cx="65" cy="65" fill="#0F0" opacity="0.5"/>
  <circle r="32" cx="50" cy="35" fill="#00F" opacity="0.5"/>
</svg>
<h3>List support:</h3>
<ol>
  <li>This</li>
  <li><p>is</p></li>
  <li>an</li>
  <li>
    ordered
    <ul>
      <li>With<br/>...<br/></li>
      <li>a</li>
      <li>nested</li>
      <li>unordered
        <ol style="list-style-type: lower-alpha;" start="5">
          <li>With a nested</li>
          <li>ordered list</li>
          <li>with a lower alpha list style</li>
          <li>starting at letter e</li>
        </ol>
      </li>
      <li>list</li>
    </ul>
  </li>
  <li>list! Lorem ipsum dolor sit amet.</li>
  <li><h2>Header 2</h2></li>
  <h2><li>Header 2</li></h2>
</ol>
<h3>Link support:</h3>
<p>
  Linking to <a href='https://github.com'>websites</a> has never been easier.
</p>
<h3>Image support:</h3>
<h3>Network png</h3>
<img alt='Google' src='https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png' />
<h3>Network svg</h3>
<img src='https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/android.svg' />
<h3>Local asset png</h3>
<img src='asset:assets/html5.png' width='100' />
<h3>Local asset svg</h3>
<img src='asset:assets/mac.svg' width='100' />
<h3>Data uri (with base64 support)</h3>
<img alt='Red dot (png)' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==' />
<img alt='Green dot (base64 svg)' src='data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB2aWV3Qm94PSIwIDAgMzAgMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxjaXJjbGUgY3g9IjE1IiBjeT0iMTAiIHI9IjEwIiBmaWxsPSJncmVlbiIvPgo8L3N2Zz4=' />
<img alt='Green dot (plain svg)' src='data:image/svg+xml,%3C?xml version="1.0" encoding="UTF-8"?%3E%3Csvg viewBox="0 0 30 20" xmlns="http://www.w3.org/2000/svg"%3E%3Ccircle cx="15" cy="10" r="10" fill="yellow"/%3E%3C/svg%3E' />
<h3>Custom source matcher (relative paths)</h3>
<img src='/wikipedia/commons/thumb/e/ef/Octicons-logo-github.svg/200px-Octicons-logo-github.svg.png' />
<h3>Custom image render (flutter.dev)</h3>
<img src='https://flutter.dev/images/flutter-mono-81x100.png' />
<h3>No image source</h3>
<img alt='No source' />
<img alt='Empty source' src='' />
<h3>Broken network image</h3>
<img alt='Broken image' src='https://www.notgoogle.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png' />
<h3>MathML Support:</h3>
<math>
<mrow>
  <mi>x</mi>
  <mo>=</mo>
  <mfrac>
    <mrow>
      <mrow>
        <mo>-</mo>
        <mi>b</mi>
      </mrow>
      <mo>&amp;PlusMinus;</mo>
      <msqrt>
        <mrow>
          <msup>
            <mi>b</mi>
            <mn>2</mn>
          </msup>
          <mo>-</mo>
          <mrow>
            <mn>4</mn>
            <mo>&amp;InvisibleTimes;</mo>
            <mi>a</mi>
            <mo>&amp;InvisibleTimes;</mo>
            <mi>c</mi>
          </mrow>
        </mrow>
      </msqrt>
    </mrow>
    <mrow>
      <mn>2</mn>
      <mo>&amp;InvisibleTimes;</mo>
      <mi>a</mi>
    </mrow>
  </mfrac>
</mrow>
</math>
<math>
  <munderover>
    <mo>&amp;int;</mo>
    <mn>0</mn>
    <mi>5</mi>
  </munderover>
  <msup>
    <mi>x</mi>
    <mn>2</mn>
  </msup>
  <mo>&amp;sdot;</mo>
  <mi>&amp;dd;</mi><mi>x</mi>
  <mo>=</mo>
  <mo>[</mo>
  <mfrac>
    <mn>1</mn>
    <mi>3</mi>
  </mfrac>
  <msup>
    <mi>x</mi>
    <mn>3</mn>
  </msup>
  <msubsup>
    <mo>]</mo>
    <mn>0</mn>
    <mn>5</mn>
  </msubsup>
  <mo>=</mo>
  <mfrac>
    <mn>125</mn>
    <mi>3</mi>
  </mfrac>
  <mo>-</mo>
  <mn>0</mn>
  <mo>=</mo>
  <mfrac>
    <mn>125</mn>
    <mi>3</mi>
  </mfrac>
</math>
<math>
  <msup>
    <mo>sin</mo>
    <mn>2</mn>
  </msup>
  <mo>&amp;theta;</mo>
  <mo>+</mo>
  <msup>
    <mo>cos</mo>
    <mn>2</mn>
  </msup>
  <mo>&amp;theta;</mo>
  <mo>=</mo>
  <mn>1</mn>
</math>
<h3>Tex Support with the custom tex tag:</h3>
<tex>i\hbar\frac{\partial}{\partial t}\Psi(\vec x,t) = -\frac{\hbar}{2m}\nabla^2\Psi(\vec x,t)+ V(\vec x)\Psi(\vec x,t)</tex>
<p id='bottom'><a href='#top'>Scroll to top</a></p>
""";

class _MyHomePageState extends State<MyHomePage> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('flutter_html Example'),
        centerTitle: true,
      ),
      body: SingleChildScrollView(
        child: Html(
          data: htmlData,
          tagsList: Html.tags..addAll(["bird", "flutter"]),
          style: {
            "table": Style(backgroundColor: Color.fromARGB(0x50, 0xee, 0xee, 0xee)),
            "tr": Style(border: Border(bottom: BorderSide(color: Colors.grey))),
            "th": Style(padding: EdgeInsets.all(6), backgroundColor: Colors.grey),
            "td": Style(padding: EdgeInsets.all(6), alignment: Alignment.topLeft),
            'h5': Style(maxLines: 2, textOverflow: TextOverflow.ellipsis),
          },
          customRender: {
            "table": (context, child) {
              return SingleChildScrollView(
                scrollDirection: Axis.horizontal,
                child: (context.tree as TableLayoutElement).toWidget(context),
              );
            },
            "bird": (RenderContext context, Widget child) {
              return TextSpan(text: "🐦");
            },
            "flutter": (RenderContext context, Widget child) {
              return FlutterLogo(
                style: (context.tree.element!.attributes['horizontal'] != null)
                    ? FlutterLogoStyle.horizontal
                    : FlutterLogoStyle.markOnly,
                textColor: context.style.color!,
                size: context.style.fontSize!.size! * 5,
              );
            },
          },
          customImageRender: {
            networkSourceMatcher(domains: ["flutter.dev"]): (context, attributes, element) {
              return FlutterLogo(size: 36);
            },
            networkSourceMatcher(domains: ["mydomain.com"]): networkImageRender(
              headers: {"Custom-Header": "some-value"},
              altWidget: (alt) => Text(alt ?? ""),
              loadingWidget: () => Text("Loading..."),
            ),
            (attr, _) => attr["src"] != null && attr["src"]!.startsWith("/wiki"):
              networkImageRender(mapUrl: (url) => "https://upload.wikimedia.org" + url!),
            networkSourceMatcher(): networkImageRender(altWidget: (_) => FlutterLogo()),
          },
          onLinkTap: (url, _, __, ___) {
            print("Opening $url...");
          },
          onImageTap: (src, _, __, ___) {
            print(src);
          },
          onImageError: (exception, stackTrace) {
            print(exception);
          },
          onCssParseError: (css, messages) {
            print("css that errored: $css");
            print("error messages:");
            messages.forEach((element) {
              print(element);
            });
          },
        ),
      ),
    );
  }
}

更多关于Flutter HTML内容渲染插件flutter_html的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter HTML内容渲染插件flutter_html的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter应用中使用flutter_html插件来渲染HTML内容的示例代码。这个插件允许你将HTML字符串直接转换为Flutter的Widget,从而在你的应用中显示复杂的HTML内容。

首先,确保你已经在pubspec.yaml文件中添加了flutter_html依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_html: ^3.0.0  # 请检查最新版本号

然后,运行flutter pub get来安装依赖。

接下来,你可以在你的Flutter应用中如下使用flutter_html

import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter HTML Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  // 示例HTML内容
  final String htmlData = """
  <h1>Hello, Flutter!</h1>
  <p>This is a paragraph with some <strong>bold</strong> and <em>italic</em> text.</p>
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
  </ul>
  <img src="https://via.placeholder.com/150" alt="Placeholder Image" />
  """;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter HTML Demo'),
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Html(
            data: htmlData,
            // 自定义样式(可选)
            customRender: (node, children) {
              if (node is dom.Element && node.tagName == 'img') {
                return Image.network(node.attributes['src'] ?? '');
              }
              return null; // 返回null以使用默认渲染
            },
            // 配置更多自定义渲染选项(可选)
            customStyleBuilder: (context, element) {
              return element.style
                ..color = Colors.black87
                ..fontSize = FontSize(16)
                ..decorationColor = Colors.blue; // 例如,链接颜色
            },
          ),
        ),
      ),
    );
  }
}

在这个示例中:

  1. HTML内容:我们定义了一个包含标题、段落、列表和图片的HTML字符串。
  2. Html Widget:使用Html widget来渲染这个HTML字符串。
  3. 自定义渲染:通过customRender回调,我们可以自定义特定HTML标签的渲染方式。在这个例子中,我们自定义了<img>标签的渲染,使其使用Image.network来显示图片。
  4. 自定义样式:通过customStyleBuilder回调,我们可以自定义HTML元素的样式。在这个例子中,我们设置了文本颜色、字体大小和链接的下划线颜色。

这个示例展示了如何使用flutter_html插件来渲染基本的HTML内容,并且展示了如何通过自定义渲染和样式来增强功能。根据你的需求,你可以进一步自定义和扩展这些功能。

回到顶部