欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net

在这里插入图片描述

1. 简介

flutter_math_fork 是一个强大的 LaTeX 数学公式渲染库,能够将 LaTeX 格式的数学公式转换为 Flutter 界面组件。该库基于 KaTeX 引擎,支持绝大多数 LaTeX 数学语法,为教育类应用、学术工具、科学计算器等提供了完整的数学公式显示能力。

在 OpenHarmony 环境下,flutter_math_fork 可以完美运行,帮助开发者实现:

  • 渲染 LaTeX 格式的数学公式
  • 支持行内公式和独立公式两种模式
  • 支持公式选择和复制功能
  • 支持公式自动换行
  • 支持自定义样式和错误处理

核心特性

  • 完整的 LaTeX 支持:支持分数、根号、积分、求和、矩阵、上下标等常用数学符号
  • 双模式渲染:支持 Math(高性能)和 SelectableMath(可选择)两种组件
  • 自定义样式:支持字体大小、颜色、粗细等样式定制
  • 错误处理:提供友好的错误回退机制
  • 公式换行:支持长公式自动换行和手动换行控制
  • 高性能渲染:基于 AST(抽象语法树)的高效渲染引擎

适用场景

  • 在线教育平台展示数学公式
  • 科学计算器显示计算过程
  • 学术论文阅读器
  • 数学笔记应用
  • 考试系统题目展示

源码仓库

  • AtomGit: https://atomgit.com/openharmony-sig/flutter_math_fork.git

2. 核心 API 讲解

2.1 Math 组件

2.1.1 Math.tex 构造函数
factory Math.tex(
  String expression, {
  Key? key,
  MathStyle mathStyle = MathStyle.display,
  TextStyle? textStyle,
  OnErrorFallback onErrorFallback = defaultOnErrorFallback,
  TexParserSettings settings = const TexParserSettings(),
  double? textScaleFactor,
  MathOptions? options,
})

参数说明:

参数名 类型 必填 默认值 说明
expression String - LaTeX 格式的数学公式字符串
mathStyle MathStyle MathStyle.display 公式样式,display 为独立公式,text 为行内公式
textStyle TextStyle null 文本样式,控制字体大小、颜色、粗细等
onErrorFallback OnErrorFallback defaultOnErrorFallback 解析错误时的回退组件
settings TexParserSettings TexParserSettings() LaTeX 解析器配置
textScaleFactor double null 文本缩放因子
options MathOptions null 完整的数学公式选项,会覆盖 mathStyletextStyle

功能说明:

Math.tex 是最常用的构造函数,直接从 LaTeX 字符串创建数学公式组件。它会先将字符串解析为抽象语法树(AST),然后渲染为 Flutter 组件。

使用场景:

  • 展示简单的数学公式
  • 高性能场景(不需要选择功能)
  • 大量公式同时显示

使用示例:

// 基础用法:显示分数
Math.tex(r'\frac{a}{b}')

// 指定样式和文本大小
Math.tex(
  r'\sqrt{x^2 + y^2}',
  mathStyle: MathStyle.display,
  textStyle: TextStyle(fontSize: 24, color: Colors.blue),
)

// 行内公式
Math.tex(
  r'E = mc^2',
  mathStyle: MathStyle.text,
  textStyle: TextStyle(fontSize: 16),
)

// 自定义错误处理
Math.tex(
  r'\invalid_command',
  onErrorFallback: (error) => Text(
    '公式错误: ${error.message}',
    style: TextStyle(color: Colors.red),
  ),
)
2.1.2 Math 构造函数
const Math({
  Key? key,
  this.ast,
  this.mathStyle = MathStyle.display,
  this.logicalPpi,
  this.onErrorFallback = defaultOnErrorFallback,
  this.options,
  this.parseError,
  this.textScaleFactor,
  this.textStyle,
})

参数说明:

参数名 类型 必填 默认值 说明
ast SyntaxTree null 已解析的抽象语法树
parseError ParseException null 解析错误
logicalPpi double null 逻辑像素每英寸,影响绝对单位的渲染大小

功能说明:

直接使用已解析的 AST 创建组件,适用于需要复用 AST 或自定义解析逻辑的场景。

使用场景:

  • 需要缓存 AST 提高性能
  • 自定义解析器
  • 需要处理解析错误

使用示例:

// 先解析 AST,再创建组件
SyntaxTree ast;
ParseException? error;
try {
  ast = SyntaxTree(
    greenRoot: TexParser(r'\frac{a}{b}', TexParserSettings()).parse(),
  );
} on ParseException catch (e) {
  error = e;
}

Math(
  ast: ast,
  parseError: error,
  textStyle: TextStyle(fontSize: 20),
)
2.1.3 texBreak 方法
BreakResult<Math> texBreak({
  int relPenalty = 500,
  int binOpPenalty = 700,
  bool enforceNoBreak = true,
})

参数说明:

参数名 类型 默认值 说明
relPenalty int 500 关系运算符换行惩罚值(0-10000)
binOpPenalty int 700 二元运算符换行惩罚值(0-10000)
enforceNoBreak bool true 是否强制禁止在 \nobreak 处换行

功能说明:

将长公式按照 TeX 规范拆分为多个部分,返回公式片段列表和对应的换行惩罚值。用于实现公式自动换行功能。

使用场景:

  • 长公式在窄屏幕上的换行
  • 自定义换行策略
  • 流式布局中的公式显示

使用示例:

// 使用 Wrap 组件自动换行
final breakResult = Math.tex(r'\sum_{i=1}^{n} x_i = x_1 + x_2 + \cdots + x_n')
    .texBreak();

Wrap(
  spacing: 8,
  children: breakResult.parts,
)

// 自定义换行策略
final breakResult = mathWidget.texBreak(
  relPenalty: 300,
  binOpPenalty: 500,
  enforceNoBreak: false,
);

// 只显示惩罚值小于 500 的换行点
final parts = breakResult.parts;
final penalties = breakResult.penalties;

2.2 SelectableMath 组件

2.2.1 SelectableMath.tex 构造函数
factory SelectableMath.tex(
  String expression, {
  Key? key,
  MathStyle mathStyle = MathStyle.display,
  TextStyle? textStyle,
  OnErrorFallback onErrorFallback = defaultOnErrorFallback,
  TexParserSettings settings = const TexParserSettings(),
  double? textScaleFactor,
  MathOptions? options,
  bool autofocus = false,
  FocusNode? focusNode,
  bool enableInteractiveSelection = true,
  bool showCursor = false,
  ToolbarOptions? toolbarOptions,
  Color? cursorColor,
  Radius? cursorRadius,
  double cursorWidth = 2.0,
  double? cursorHeight,
  TextSelectionControls? textSelectionControls,
  DragStartBehavior dragStartBehavior = DragStartBehavior.start,
})

参数说明:

参数名 类型 默认值 说明
autofocus bool false 是否自动获取焦点
focusNode FocusNode null 焦点节点
enableInteractiveSelection bool true 是否启用交互式选择
showCursor bool false 是否显示光标
toolbarOptions ToolbarOptions null 工具栏选项(复制、全选等)
cursorColor Color null 光标颜色
cursorRadius Radius null 光标圆角半径
cursorWidth double 2.0 光标宽度
cursorHeight double null 光标高度

功能说明:

SelectableMathMath 的基础上增加了选择功能,用户可以长按选择公式的部分或全部内容,并复制到剪贴板。

使用场景:

  • 需要用户复制公式
  • 公式编辑器
  • 学习笔记应用

使用示例:

// 基础用法
SelectableMath.tex(r'\frac{a}{b}')

// 自定义工具栏
SelectableMath.tex(
  r'\int_0^1 x^2 dx',
  toolbarOptions: ToolbarOptions(
    copy: true,
    selectAll: true,
    cut: false,
    paste: false,
  ),
)

// 自定义光标
SelectableMath.tex(
  r'\sum_{i=1}^n i = \frac{n(n+1)}{2}',
  cursorColor: Colors.blue,
  cursorWidth: 3.0,
  showCursor: true,
)

2.3 MathOptions 配置

2.3.1 MathOptions 构造函数
factory MathOptions({
  MathStyle style = MathStyle.display,
  Color color = Colors.black,
  MathSize sizeUnderTextStyle = MathSize.normalsize,
  FontOptions? textFontOptions,
  FontOptions? mathFontOptions,
  double? fontSize,
  double? logicalPpi,
})

参数说明:

参数名 类型 默认值 说明
style MathStyle MathStyle.display 公式样式
color Color Colors.black 公式颜色
sizeUnderTextStyle MathSize MathSize.normalsize 公式大小
textFontOptions FontOptions null 文本模式字体选项
mathFontOptions FontOptions null 数学模式字体选项
fontSize double null 字体大小
logicalPpi double null 逻辑像素每英寸

功能说明:

MathOptions 封装了数学公式的所有渲染选项,可以一次性配置多个属性。

使用示例:

// 创建自定义选项
final options = MathOptions(
  style: MathStyle.display,
  color: Colors.deepPurple,
  fontSize: 28,
  mathFontOptions: FontOptions(
    fontWeight: FontWeight.bold,
  ),
);

Math.tex(
  r'\alpha + \beta = \gamma',
  options: options,
)

2.4 枚举和类型

2.4.1 MathStyle
enum MathStyle {
  display,   // 独立公式样式,居中显示,较大字号
  text,      // 行内公式样式,较小字号
  script,    // 脚本样式,用于上下标
  scriptScript, // 小脚本样式
}

功能说明:

控制公式的渲染样式,影响符号大小、间距等。

2.4.2 MathSize
enum MathSize {
  tiny,
  Small,
  footnotesize,
  small,
  normalsize,
  large,
  Large,
  LARGE,
  huge,
  Huge,
}

功能说明:

控制公式的字号大小,类似 LaTeX 的字号命令。

2.5 错误处理

2.5.1 OnErrorFallback
typedef OnErrorFallback = Widget Function(FlutterMathException errmsg);

功能说明:

当公式解析或渲染失败时的回退组件。

使用示例:

Math.tex(
  r'\invalid',
  onErrorFallback: (error) {
    if (error is ParseException) {
      return Text('解析错误: ${error.message}');
    }
    return Text('渲染错误');
  },
)
2.5.2 defaultOnErrorFallback
static Widget defaultOnErrorFallback(FlutterMathException error) =>
    SelectableText(error.messageWithType);

功能说明:

默认的错误回退组件,显示错误信息。

3. 使用示例

3.1 基础公式显示

import 'package:flutter/material.dart';
import 'package:flutter_math_fork/flutter_math.dart';

// 分数
Math.tex(r'\frac{a}{b}')

// 根号
Math.tex(r'\sqrt{x^2 + y^2}')

// 积分
Math.tex(r'\int_0^1 x^2 dx')

// 求和
Math.tex(r'\sum_{i=1}^{n} i = \frac{n(n+1)}{2}')

// 矩阵
Math.tex(r'\begin{pmatrix} a & b \\ c & d \end{pmatrix}')

3.2 行内公式

Row(
  children: [
    Text('根据公式 '),
    Math.tex(
      r'E = mc^2',
      mathStyle: MathStyle.text,
      textStyle: TextStyle(fontSize: 16),
    ),
    Text(',我们可以得出'),
  ],
)

3.3 可选择公式

SelectableMath.tex(
  r'\frac{\partial f}{\partial x} = \lim_{h \to 0} \frac{f(x+h) - f(x)}{h}',
  toolbarOptions: ToolbarOptions(
    copy: true,
    selectAll: true,
  ),
)

3.4 自定义样式

Math.tex(
  r'\alpha + \beta = \gamma',
  textStyle: TextStyle(
    fontSize: 32,
    color: Colors.deepPurple,
    fontWeight: FontWeight.bold,
  ),
)

3.5 错误处理

Math.tex(
  r'\invalid_command',
  onErrorFallback: (error) => Container(
    padding: EdgeInsets.all(8),
    decoration: BoxDecoration(
      color: Colors.red.shade50,
      borderRadius: BorderRadius.circular(8),
      border: Border.all(color: Colors.red),
    ),
    child: Text(
      '公式解析失败: ${error.message}',
      style: TextStyle(color: Colors.red),
    ),
  ),
)

4. 完整代码

4.1 数学公式学习平台

在这里插入图片描述

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_math_fork/flutter_math.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '数学公式学习平台',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.indigo,
          brightness: Brightness.light,
        ),
        useMaterial3: true,
      ),
      home: const MathLearningScreen(),
    );
  }
}

class MathFormula {
  final String title;
  final String latex;
  final String category;
  final String description;

  const MathFormula({
    required this.title,
    required this.latex,
    required this.category,
    required this.description,
  });
}

class MathLearningScreen extends StatefulWidget {
  const MathLearningScreen({super.key});

  
  State<MathLearningScreen> createState() => _MathLearningScreenState();
}

class _MathLearningScreenState extends State<MathLearningScreen>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;
  String _searchQuery = '';

  final List<MathFormula> _formulas = const [
    MathFormula(
      title: '勾股定理',
      latex: r'a^2 + b^2 = c^2',
      category: '几何',
      description: '直角三角形两直角边的平方和等于斜边的平方',
    ),
    MathFormula(
      title: '二次方程求根公式',
      latex: r'x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}',
      category: '代数',
      description: '一元二次方程 ax²+bx+c=0 的求根公式',
    ),
    MathFormula(
      title: '三角恒等式',
      latex: r'\sin^2\theta + \cos^2\theta = 1',
      category: '三角函数',
      description: '正弦平方加余弦平方等于 1',
    ),
    MathFormula(
      title: '欧拉公式',
      latex: r'e^{i\pi} + 1 = 0',
      category: '高等数学',
      description: '数学中最优美的公式之一',
    ),
    MathFormula(
      title: '导数定义',
      latex: r"f'(x) = \lim_{h \to 0} \frac{f(x+h) - f(x)}{h}",
      category: '微积分',
      description: '函数在某一点的导数定义',
    ),
    MathFormula(
      title: '定积分',
      latex: r'\int_a^b f(x)dx = F(b) - F(a)',
      category: '微积分',
      description: '牛顿-莱布尼茨公式',
    ),
    MathFormula(
      title: '求和公式',
      latex: r'\sum_{i=1}^{n} i = \frac{n(n+1)}{2}',
      category: '数列',
      description: '等差数列前 n 项和公式',
    ),
    MathFormula(
      title: '等比数列求和',
      latex: r'S_n = \frac{a_1(1-q^n)}{1-q}',
      category: '数列',
      description: '等比数列前 n 项和公式',
    ),
    MathFormula(
      title: '矩阵乘法',
      latex: r'\begin{pmatrix} a & b \\ c & d \end{pmatrix} \begin{pmatrix} x \\ y \end{pmatrix} = \begin{pmatrix} ax+by \\ cx+dy \end{pmatrix}',
      category: '线性代数',
      description: '2×2 矩阵与向量的乘法',
    ),
    MathFormula(
      title: '圆的面积',
      latex: r'S = \pi r^2',
      category: '几何',
      description: '圆的面积公式',
    ),
    MathFormula(
      title: '球体体积',
      latex: r'V = \frac{4}{3}\pi r^3',
      category: '几何',
      description: '球体的体积公式',
    ),
    MathFormula(
      title: '泰勒展开',
      latex: r'e^x = \sum_{n=0}^{\infty} \frac{x^n}{n!}',
      category: '高等数学',
      description: '指数函数的泰勒级数展开',
    ),
    MathFormula(
      title: '高斯积分',
      latex: r'\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}',
      category: '微积分',
      description: '高斯积分公式',
    ),
    MathFormula(
      title: '三角和差公式',
      latex: r'\sin(\alpha \pm \beta) = \sin\alpha\cos\beta \pm \cos\alpha\sin\beta',
      category: '三角函数',
      description: '正弦的和差角公式',
    ),
    MathFormula(
      title: '行列式',
      latex: r'\det\begin{pmatrix} a & b \\ c & d \end{pmatrix} = ad - bc',
      category: '线性代数',
      description: '2×2 矩阵的行列式',
    ),
  ];

  
  void initState() {
    super.initState();
    final categories = _formulas.map((f) => f.category).toSet().toList();
    _tabController = TabController(length: categories.length, vsync: this);
  }

  
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  List<MathFormula> get _filteredFormulas {
    var formulas = _formulas;
    if (_searchQuery.isNotEmpty) {
      formulas = formulas
          .where((f) =>
              f.title.contains(_searchQuery) ||
              f.description.contains(_searchQuery) ||
              f.latex.contains(_searchQuery))
          .toList();
    }
    return formulas;
  }

  List<String> get _categories {
    return _formulas.map((f) => f.category).toSet().toList();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
        headerSliverBuilder: (context, innerBoxIsScrolled) => [
          SliverAppBar(
            expandedHeight: 220,
            floating: true,
            pinned: true,
            flexibleSpace: FlexibleSpaceBar(
              titlePadding: const EdgeInsets.only(left: 16, bottom: 16),
              title: const Text(
                '数学公式学习平台',
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  shadows: [
                    Shadow(
                      color: Colors.black54,
                      blurRadius: 4,
                      offset: Offset(0, 2),
                    ),
                  ],
                ),
              ),
              background: Container(
                decoration: BoxDecoration(
                  gradient: LinearGradient(
                    begin: Alignment.topLeft,
                    end: Alignment.bottomRight,
                    colors: [
                      Colors.indigo.shade600,
                      Colors.indigo.shade400,
                      Colors.blue.shade400,
                    ],
                  ),
                ),
                child: Center(
                  child: Icon(
                    Icons.functions,
                    size: 80,
                    color: Colors.white.withOpacity(0.3),
                  ),
                ),
              ),
            ),
            bottom: PreferredSize(
              preferredSize: const Size.fromHeight(120),
              child: Column(
                children: [
                  Padding(
                    padding: const EdgeInsets.symmetric(
                      horizontal: 16,
                      vertical: 8,
                    ),
                    child: TextField(
                      decoration: InputDecoration(
                        hintText: '搜索公式...',
                        prefixIcon: const Icon(Icons.search),
                        suffixIcon: _searchQuery.isNotEmpty
                            ? IconButton(
                                icon: const Icon(Icons.clear),
                                onPressed: () {
                                  setState(() {
                                    _searchQuery = '';
                                  });
                                },
                              )
                            : null,
                        filled: true,
                        fillColor: Colors.white,
                        border: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(24),
                          borderSide: BorderSide.none,
                        ),
                        contentPadding: const EdgeInsets.symmetric(
                          horizontal: 16,
                          vertical: 8,
                        ),
                      ),
                      onChanged: (value) {
                        setState(() {
                          _searchQuery = value;
                        });
                      },
                    ),
                  ),
                  TabBar(
                    controller: _tabController,
                    isScrollable: true,
                    tabs: _categories.map((category) => Tab(text: category)).toList(),
                  ),
                ],
              ),
            ),
          ),
        ],
        body: TabBarView(
          controller: _tabController,
          children: _categories.map((category) {
            final categoryFormulas = _filteredFormulas
                .where((f) => f.category == category)
                .toList();
            return _buildFormulaList(categoryFormulas);
          }).toList(),
        ),
      ),
    );
  }

  Widget _buildFormulaList(List<MathFormula> formulas) {
    if (formulas.isEmpty) {
      return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(
              Icons.search_off,
              size: 80,
              color: Colors.grey.shade400,
            ),
            const SizedBox(height: 16),
            Text(
              '没有找到匹配的公式',
              style: TextStyle(
                fontSize: 16,
                color: Colors.grey.shade600,
              ),
            ),
          ],
        ),
      );
    }

    return ListView.builder(
      padding: const EdgeInsets.all(16),
      itemCount: formulas.length,
      itemBuilder: (context, index) {
        final formula = formulas[index];
        return _buildFormulaCard(formula);
      },
    );
  }

  Widget _buildFormulaCard(MathFormula formula) {
    return Card(
      margin: const EdgeInsets.only(bottom: 16),
      elevation: 4,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 12,
                    vertical: 6,
                  ),
                  decoration: BoxDecoration(
                    gradient: LinearGradient(
                      colors: [
                        Colors.indigo.shade400,
                        Colors.indigo.shade600,
                      ],
                    ),
                    borderRadius: BorderRadius.circular(12),
                  ),
                  child: Text(
                    formula.category,
                    style: const TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.bold,
                      fontSize: 12,
                    ),
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: Text(
                    formula.title,
                    style: const TextStyle(
                      fontSize: 18,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
                IconButton(
                  icon: const Icon(Icons.copy, size: 20),
                  onPressed: () {
                    Clipboard.setData(ClipboardData(text: formula.latex));
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(
                        content: const Text('已复制到剪贴板'),
                        behavior: SnackBarBehavior.floating,
                        duration: const Duration(seconds: 1),
                      ),
                    );
                  },
                  tooltip: '复制 LaTeX',
                ),
              ],
            ),
            const SizedBox(height: 16),
            Container(
              constraints: const BoxConstraints(maxHeight: 120),
              padding: const EdgeInsets.symmetric(vertical: 12),
              decoration: BoxDecoration(
                color: Colors.grey.shade50,
                borderRadius: BorderRadius.circular(12),
                border: Border.all(color: Colors.grey.shade200),
              ),
              child: SingleChildScrollView(
                scrollDirection: Axis.horizontal,
                padding: const EdgeInsets.symmetric(horizontal: 16),
                child: SelectableMath.tex(
                  formula.latex,
                  mathStyle: MathStyle.display,
                  textStyle: const TextStyle(fontSize: 22),
                ),
              ),
            ),
            const SizedBox(height: 12),
            Text(
              formula.description,
              style: TextStyle(
                fontSize: 14,
                color: Colors.grey.shade700,
                height: 1.5,
              ),
            ),
            const SizedBox(height: 12),
            Container(
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: Colors.indigo.shade50,
                borderRadius: BorderRadius.circular(8),
              ),
              child: Row(
                children: [
                  const Icon(Icons.code, size: 16, color: Colors.indigo),
                  const SizedBox(width: 8),
                  Expanded(
                    child: Text(
                      formula.latex,
                      style: TextStyle(
                        fontSize: 12,
                        fontFamily: 'monospace',
                        color: Colors.indigo.shade700,
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

4.2 依赖配置

pubspec.yaml 中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_math_fork:
    git:
      url: https://atomgit.com/openharmony-sig/flutter_math_fork.git
      ref: br_v0.7.4_ohos

4.3 运行效果

运行应用后,你将看到:

  1. 顶部应用栏:带有渐变背景和图标,显示"数学公式学习平台"标题
  2. 搜索框:支持按标题、描述、LaTeX 源码搜索公式
  3. 分类标签栏:按几何、代数、三角函数、微积分等分类浏览
  4. 公式卡片
    • 分类标签和标题
    • 可选择的公式渲染区域
    • 公式描述
    • LaTeX 源码展示
    • 一键复制按钮

4.4 功能特点

  • 丰富的公式库:内置 15 个常用数学公式,涵盖多个数学分支
  • 分类浏览:按几何、代数、三角函数、微积分等分类组织
  • 搜索功能:支持按标题、描述、LaTeX 源码搜索
  • 公式选择:支持长按选择公式内容
  • 一键复制:快速复制 LaTeX 源码到剪贴板
  • 精美 UI 设计:Material Design 3 风格,渐变背景、圆角卡片、阴影效果
  • 完整交互体验:搜索、分类切换、复制提示等

5. 注意事项

  1. 性能优化:大量公式同时显示时,建议使用 Math 而非 SelectableMath,前者性能更优
  2. 转义字符:LaTeX 字符串建议使用原始字符串(r'...'),避免转义问题
  3. 错误处理:务必提供 onErrorFallback,避免公式解析失败导致应用崩溃
  4. 字体大小:通过 textStyle.fontSize 控制公式大小,建议 16-32 之间
  5. 行内公式:使用 MathStyle.text 显示行内公式,字号会自动缩小
  6. 独立公式:使用 MathStyle.display 显示独立公式,居中且字号较大
  7. 换行支持:长公式可使用 texBreak() 方法实现自动换行
  8. OpenHarmony 适配:使用 AtomGit 的 OpenHarmony 适配版本,确保在鸿蒙设备上正常运行

6. 总结

flutter_math_fork 是 Flutter 生态中最完善的 LaTeX 数学公式渲染库,在 OpenHarmony 环境下可以完美运行。通过本文章的学习,我们掌握了:

  • Math.texSelectableMath.tex 的使用方法和区别
  • MathOptions 配置公式样式、颜色、大小等选项
  • MathStyle 控制行内公式和独立公式的显示模式
  • texBreak() 方法实现公式自动换行
  • 自定义错误处理机制
  • 完整的"数学公式学习平台"应用实现

通过 flutter_math_fork,你可以轻松实现在线教育平台、科学计算器、学术论文阅读器、数学笔记应用等需要展示数学公式的场景,为 OpenHarmony 应用增添强大的数学公式渲染能力。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐