Sử dụng thư viện flutter_tex để render công thức toán

Việc tạo và hiển thị công thức toán, lý, hóa dùng phần mềm như word, laTex, MathType đã không còn xa lạ với nhiều người. Trong bài viết này mình sẽ trình bày cách để hiển thị được các công thức này trên mobile app, cụ thể là framework Flutter.

1. Cài đặt thư viện

1.1. Chạy câu lệnh cài đặt

flutter pub add flutter_tex

Sau khi hoàn tất, file package pubspec.yaml sẽ có thêm dependency sau

dependencies:
  flutter_tex: ^4.0.3+4

1.2. Import các cài đặt cần thiết

Flutter có 3 folder tương ứng với 3 nền tảng chạy ứng dụng là android, ios và web. Mình sẽ lần lượt thêm các configuration vào 3 folder này như sau.

Android

Thêm vào file android/app/src/main/AndroidManifest.xml như sau

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<application
       ...
       ...
       android:usesCleartextTraffic="true">
</application>

Vì package flutter_tex sử dụng webview nên yêu cầu quyền truy cập internet, do đó ta phải thêm user-permission như trên, còn về bản chất ứng dụng vẫn hoạt động offline.

iOS

Thêm vào file ios/Runner/Info.plist như sau

<key>NSAppTransportSecurity</key>
  <dict>
    <key>NSAllowsArbitraryLoads</key> <true/>
  </dict>
<key>io.flutter.embedded_views_preview</key> <true/> 

web

Thêm vào file web/index.html như sau

<head>
  
    <meta charset="UTF-8">
    <title>Flutter TeX</title>

    <script src="assets/packages/flutter_tex/js/flutter_tex.js"></script>
    <script type="text/javascript">window.flutterWebRenderer = "canvaskit";</script>
</head>

File flutter_tex.js có thể lấy ở link sau
https://github.com/shah-xad/flutter_tex/blob/master/lib/js/flutter_tex.js

2. Sử dụng thư viện

2.1. Import thư viện

import 'package:flutter_tex/flutter_tex.dart';

2.2. Thư viện có các component chính sau

TeXViewWidget là abstract widget, các widget khác đều kế thừa từ widget này, ví dụ như TeXViewDocument, TeXViewMarkdown, TeXViewImage, TeXViewColumn, ...

TeXView là một class giúp hiển thị công thức, với đầy đủ các property như child, fonts, style, trong đó child là TeXViewWidget sẽ được render.

2.3. Chạy thử một example

Mình sẽ chạy lại example dưới đây của thư viện (đã được chỉnh sửa cho gọn)

Code

Khai báo công thức dùng widget TeXViewWidget

class TeXExample chứa 2 field quadraticEquation và bohrRadius, cả 2 đều có type là TeXViewWidget.

class TeXExample {
  static TeXViewWidget quadraticEquation =
      _teXViewWidget(r"<h4>Quadratic Equation</h4>", r"""
     When \(a \ne 0 \), there are two solutions to \(ax^2 + bx + c = 0\) and they are
     $$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$<br>""");
     
  static TeXViewWidget bohrRadius = _teXViewWidget(r"<h4>Bohr's Radius</h4>",
      r"""\( a_0 = \frac{{\hbar ^2 }}{{m_e ke^2 }} \)""");
     
  static TeXViewWidget _teXViewWidget(String title, String body) {
    return TeXViewColumn(
        style: const TeXViewStyle(
            margin: TeXViewMargin.all(10),
            padding: TeXViewPadding.all(10),
            borderRadius: TeXViewBorderRadius.all(10),
            border: TeXViewBorder.all(TeXViewBorderDecoration(
                borderWidth: 2,
                borderStyle: TeXViewBorderStyle.groove,
                borderColor: Colors.green))),
        children: [
          TeXViewDocument(title,
              style: const TeXViewStyle(
                  padding: TeXViewPadding.all(10),
                  borderRadius: TeXViewBorderRadius.all(10),
                  textAlign: TeXViewTextAlign.center,
                  width: 250,
                  margin: TeXViewMargin.zeroAuto(),
                  backgroundColor: Colors.green)),
          TeXViewDocument(body,
              style: const TeXViewStyle(margin: TeXViewMargin.only(top: 10)))
        ]);
  }
}

Render 2 phương trình quadraticEquation và bohrRadius như sau

class TeXViewDocumentExamples extends StatelessWidget {
  final TeXViewRenderingEngine renderingEngine;

  const TeXViewDocumentExamples(
      {Key? key, this.renderingEngine = const TeXViewRenderingEngine.katex()})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        title: const Text("TeXViewDocument"),
      ),
      body: TeXView(
        renderingEngine: renderingEngine,
        child: TeXViewColumn(children: [
          TeXExample.quadraticEquation,
          TeXExample.bohrRadius,
          if (renderingEngine.name == 'mathjax') ...[TeXExample.others]
        ]),
        style: const TeXViewStyle(
          margin: TeXViewMargin.all(10),
          elevation: 10,
          borderRadius: TeXViewBorderRadius.all(25),
          border: TeXViewBorder.all(
            TeXViewBorderDecoration(
                borderColor: Colors.blue,
                borderStyle: TeXViewBorderStyle.solid,
                borderWidth: 5),
          ),
          backgroundColor: Colors.white,
        ),
      ),
    );
  }
}

Kết qủa

Như ta thấy được các công thức latex đã được render chính xác.

Tham khảo

https://pub.dev/packages/flutter_tex