Flutter HTML渲染插件flutter_html_v3的使用

Flutter HTML渲染插件flutter_html_v3的使用

简介

flutter_html 是一个用于将HTML和CSS渲染为Flutter小部件的库。它支持多种HTML标签和CSS属性,并允许开发者自定义渲染行为。

安装

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

dependencies:
  flutter_html: ^3.0.0-alpha.5
  // 或者
  // flutter_html_all: ^3.0.0-alpha.5 包括表格、视频、音频、iframe等

支持的HTML标签

标签 描述
<a> 锚点链接
<abbr> 缩写词
<acronym> 首字母缩略词
<address> 地址信息
<article> 文章
<aside> 侧边栏
<audio> 音频
<b> 加粗文本
<bdi> 文本方向隔离
<bdo> 文本方向覆盖
<big> 大字体文本
<blockquote> 引用块
<body> 文档主体
<br> 换行符
<caption> 表格标题
<cite> 引用
<code> 代码片段
<data> 数字数据
<dd> 详细描述
<del> 删除线文本
<details> 详情
<dfn> 定义
<div> 分区容器
<dl> 定义列表
<dt> 定义项
<em> 强调文本
<figcaption> 图片说明
<figure> 图片或图表
<footer> 页脚
<font> 字体样式
<h1> 一级标题
<h2> 二级标题
<h3> 三级标题
<h4> 四级标题
<h5> 五级标题
<h6> 六级标题
<header> 页眉
<hr> 水平线
<i> 斜体文本
<iframe> 嵌入框架
<img> 图像
<ins> 下划线文本
<kbd> 键盘输入
<li> 列表项
<main> 主要内容
<mark> 标记文本
<nav> 导航链接
<noscript> 不支持脚本时的内容
<ol> 有序列表
<p> 段落
<pre> 预格式化文本
<q> 引用
<rp> Ruby注音
<rt> Ruby注音文本
<ruby> Ruby注音
<s> 删除线文本
<samp> 样本输出
<section>
<small> 小字体文本
<span> 内联容器
<strike> 删除线文本
<strong> 加强文本
<sub> 下标
<sup> 上标
<summary> 摘要
<svg> SVG图像
<table> 表格
<tbody> 表格主体
<td> 单元格
<template> 模板
<tfoot> 表格底部
<th> 表头单元格
<thead> 表头
<time> 时间
<tr>
<tt> 打字机风格文本
<ul> 无序列表
<var> 变量
<video> 视频
<math> MathML公式
<mrow> MathML公式元素
<msup> MathML上标
<msub> MathML下标
<mover> MathML上标
<munder> MathML下标
<msubsup> MathML上下标
<moverunder> MathML上下标
<mfrac> MathML分数
<mlongdiv> MathML长除法
<msqrt> MathML平方根
<mroot> MathML根号
<mi> MathML标识符
<mn> MathML数字
<mo> MathML操作符

支持的CSS属性

属性 描述
background-color 背景颜色
color 文本颜色
direction 文本方向
display 显示类型
font-family 字体系列
font-feature-settings 字体特性
font-size 字体大小
font-style 字体样式
font-weight 字体粗细
height 高度
letter-spacing 字母间距
line-height 行高
list-style-type 列表项目符号类型
list-style-position 列表项目符号位置
padding 内边距
margin 外边距
text-align 文本对齐方式
text-decoration 文本修饰
text-decoration-color 文本修饰颜色
text-decoration-style 文本修饰样式
text-decoration-thickness 文本修饰厚度
text-shadow 文本阴影
vertical-align 垂直对齐
white-space 白空间处理
width 宽度
word-spacing 字符间距

支持的内联CSS属性

属性 描述
background-color 背景颜色
border (包括特定方向) 边框
color 文本颜色
direction 文本方向
display 显示类型
font-family 字体系列
font-feature-settings 字体特性
font-size 字体大小
font-style 字体样式
font-weight 字体粗细
line-height 行高
list-style-type 列表项目符号类型
list-style-position 列表项目符号位置
padding (包括特定方向) 内边距
margin (包括特定方向) 外边距
text-align 文本对齐方式
text-decoration 文本修饰
text-decoration-color 文本修饰颜色
text-decoration-style 文本修饰样式
text-shadow 文本阴影

使用示例

数据参数

Widget html = Html(
  data: """
    <div>
      <h1>Demo Page</h1>
      <p>This is a fantastic product that you should buy!</p>
      <h3>Features</h3>
      <ul>
        <li>It actually works</li>
        <li>It exists</li>
        <li>It doesn't cost much!</li>
      </ul>
      <!--You can pretty much put any html in here!-->
    </div>
  """,
);

文档参数

import 'package:html/parser.dart' as htmlparser;
import 'package:html/dom.dart' as dom;

String htmlData = """
  <div>
    <h1>Demo Page</h1>
    <p>This is a fantastic product that you should buy!</p>
    <h3>Features</h3>
    <ul>
      <li>It actually works</li>
      <li>It exists</li>
      <li>It doesn't cost much!</li>
    </ul>
    <!--You can pretty much put any html in here!-->
  </div>
""";
dom.Document document = htmlparser.parse(htmlData);

Widget html = Html(
  document: document,
);

链接点击事件

Widget html = Html(
  data: """
    <p>
     Linking to <a href='https://github.com'>websites</a> has never been easier.
    </p>
  """,
  onLinkTap: (String? url, RenderContext context, Map<String, String> attributes, dom.Element? element) {
    // 打开URL到WebView,或者在浏览器中打开URL,或者其他逻辑
  }
);

自定义渲染

Widget html = Html(
  data: """
    <h3>Display bird element and flutter element <bird></bird></h3>
    <flutter></flutter>
    <flutter horizontal></flutter>
  """,
  customRenders: {
    birdMatcher(): CustomRender.inlineSpan(inlineSpan: (context, buildChildren) => TextSpan(text: "🐦")),
    flutterMatcher(): CustomRender.widget(widget: (context, buildChildren) => FlutterLogo(
      style: (context.tree.element!.attributes['horizontal'] != null)
          ? FlutterLogoStyle.horizontal
          : FlutterLogoStyle.markOnly,
      textColor: context.style.color!,
      size: context.style.fontSize!.size! * 5,
    )),
  },
  tagsList: Html.tags..addAll(["bird", "flutter"]),
);

CustomRenderMatcher birdMatcher() => (context) => context.tree.element?.localName == 'bird';

CustomRenderMatcher flutterMatcher() => (context) => context.tree.element?.localName == 'flutter';

图片加载错误处理

Widget html = Html(
  data: """
    <img alt='Alt Text of an intentionally broken image' src='https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30d'/>
  """,
  onImageError: (Exception exception, StackTrace stackTrace) {
    FirebaseCrashlytics.instance.recordError(exception, stackTrace);
  },
);

图片点击事件

Widget html = Html(
  data: """
    <img alt='Google' src='https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png' />
  """,
  onImageTap: (String? url, RenderContext context, Map<String, String> attributes, dom.Element? element) {
    // 打开图片到WebView,或者在浏览器中打开图片,或者其他逻辑
  }
);

渲染指定标签

Widget html = Html(
  data: """
    <p>Render this item</p>
    <span>Do not render this item or any other item</span>
    <img src='https://flutter.dev/images/flutter-mono-81x100.png'/>
  """,
  tagsList: ['p']
);

自定义样式

Widget html = Html(
  data: """
    <h1>Table support:</h1>
    <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<br>Rowspan<br>Rowspan<br>Rowspan<br>Rowspan<br>Rowspan<br>Rowspan<br>Rowspan<br>Rowspan<br>Rowspan</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>
  """,
  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元素文本颜色
    "h1": Style(color: Colors.red),
  }
);

自定义渲染示例

自定义HTML标签

Widget html = Html(
  data: """
    <h3>Display bird element and flutter element <bird></bird></h3>
    <flutter></flutter>
    <flutter horizontal></flutter>
  """,
  customRenders: {
    birdMatcher(): CustomRender.inlineSpan(inlineSpan: (context, buildChildren) => TextSpan(text: "🐦")),
    flutterMatcher(): CustomRender.widget(widget: (context, buildChildren) => FlutterLogo(
      style: (context.tree.element!.attributes['horizontal'] != null)
          ? FlutterLogoStyle.horizontal
          : FlutterLogoStyle.markOnly,
      textColor: context.style.color!,
      size: context.style.fontSize!.size! * 5,
    )),
  },
  tagsList: Html.tags..addAll(["bird", "flutter"]),
);

CustomRenderMatcher birdMatcher() => (context) => context.tree.element?.localName == 'bird';

CustomRenderMatcher flutterMatcher() => (context) => context.tree.element?.localName == 'flutter';

自定义iframe渲染

Widget html = Html(
  data: """
    <h3>Google iframe:</h3>
    <iframe src="https://google.com"></iframe>
    <h3>YouTube iframe:</h3>
    <iframe src="https://www.youtube.com/embed/tgbNymZ7vqY"></iframe>
  """,
  customRenders: {
    iframeYT(): CustomRender.widget(widget: (context, buildChildren) {
      double? width = double.tryParse(context.tree.attributes['width'] ?? "");
      double? height = double.tryParse(context.tree.attributes['height'] ?? "");
      return Container(
        width: width ?? (height ?? 150) * 2,
        height: height ?? (width ?? 300) / 2,
        child: WebView(
          initialUrl: context.tree.attributes['src']!,
          javascriptMode: JavascriptMode.unrestricted,
          navigationDelegate: (NavigationRequest request) async {
            // 当显示嵌入式YouTube视频时,不需要加载其他URL,因此阻止URL加载
            if (!request.url.contains("youtube.com/embed")) {
              return NavigationDecision.prevent;
            } else {
              return NavigationDecision.navigate;
            }
          },
        ),
      );
    }),
    iframeOther(): CustomRender.widget(widget: (context, buildChildren) {
      double? width = double.tryParse(context.tree.attributes['width'] ?? "");
      double? height = double.tryParse(context.tree.attributes['height'] ?? "");
      return Container(
        width: width ?? (height ?? 150) * 2,
        height: height ?? (width ?? 300) / 2,
        child: WebView(
          initialUrl: context.tree.attributes['src'],
          javascriptMode: JavascriptMode.unrestricted,
          // 其他iframe内容可能需要滚动,因此使用VerticalDragGestureRecognizer
          gestureRecognizers: [
            Factory(() => VerticalDragGestureRecognizer())
          ].toSet(),
        ),
      );
    }),
    iframeNull(): CustomRender.widget(widget: (context, buildChildren) => Container(height: 0, width: 0)),
  }
);

CustomRenderMatcher iframeYT() => (context) => context.tree.element?.attributes['src']?.contains("youtube.com/embed") ?? false;

CustomRenderMatcher iframeOther() => (context) => !(context.tree.element?.attributes['src']?.contains("youtube.com/embed")
  ?? context.tree.element?.attributes['src'] == null);

CustomRenderMatcher iframeNull() => (context) => context.tree.element?.attributes['src'] == null;

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

1 回复

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


flutter_html 是一个用于在 Flutter 应用中渲染 HTML 内容的插件。它支持大部分的 HTML 标签,并且可以自定义样式和渲染行为。flutter_html 的第三个版本(flutter_html_v3)在性能和功能上都有所提升。

以下是使用 flutter_html_v3 的基本步骤:

1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加 flutter_html 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_html: ^3.0.0-alpha.2

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

2. 基本使用

在你的 Flutter 应用中,你可以使用 Html 组件来渲染 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(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter HTML Example'),
        ),
        body: SingleChildScrollView(
          child: Html(
            data: """
              <h1>Heading 1</h1>
              <p>This is a paragraph with <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" />
              <a href="https://flutter.dev">Visit Flutter</a>
            """,
          ),
        ),
      ),
    );
  }
}

3. 自定义样式

你可以通过 style 参数来自定义 HTML 标签的样式。style 参数接受一个 Map<String, Style>,其中键是 CSS 选择器,值是一个 Style 对象。

Html(
  data: """
    <h1>Heading 1</h1>
    <p>This is a paragraph with <strong>bold</strong> and <em>italic</em> text.</p>
  """,
  style: {
    "h1": Style(
      fontSize: FontSize.larger,
      fontWeight: FontWeight.bold,
      color: Colors.blue,
    ),
    "p": Style(
      fontSize: FontSize.medium,
      color: Colors.black87,
    ),
    "strong": Style(
      fontWeight: FontWeight.bold,
      color: Colors.red,
    ),
    "em": Style(
      fontStyle: FontStyle.italic,
      color: Colors.green,
    ),
  },
)

4. 处理链接和图片

flutter_html 提供了回调函数来处理链接和图片的点击事件。

Html(
  data: """
    <a href="https://flutter.dev">Visit Flutter</a>
    <img src="https://via.placeholder.com/150" alt="Placeholder Image" />
  """,
  onLinkTap: (url, _, __, ___) {
    print("Link tapped: $url");
  },
  onImageTap: (src, _, __, ___) {
    print("Image tapped: $src");
  },
)

5. 自定义渲染

如果你需要更高级的自定义渲染,你可以使用 customRender 参数。customRender 允许你为特定的 HTML 标签定义自定义的渲染逻辑。

Html(
  data: """
    <custom-tag>Custom Content</custom-tag>
  """,
  customRender: {
    "custom-tag": (context, child) {
      return Container(
        padding: EdgeInsets.all(10),
        color: Colors.yellow,
        child: Text("Custom Render: ${context.tree.element?.text}"),
      );
    },
  },
)
回到顶部