FlutterアプリでMarkdownテキストを美しく表示したい、AI生成コンテンツをリッチに表現したいと思ったことはありませんか? そんなときに最適なのが flutter_md
パッケージです。高性能で軽量なMarkdownパーサー・レンダラーとして、特にAIアシスタントのコンテンツ表示に最適化されています。
1. flutter_mdとは?
flutter_md
は、Flutter専用に設計された高性能で軽量なMarkdownパーサー・レンダラーです。ChatGPT、Gemini、その他のLLM(大規模言語モデル)からのフォーマット済みテキスト表示に最適化されています。
主な特徴:
- 高性能:最適化された解析で最小限のメモリフットプリント
- 完全カスタマイズ可能:テーマベーススタイリング
- Flutter ネイティブ:カスタムレンダーオブジェクトを使用
- インタラクティブ要素:クリック可能なリンク
- クロスプラットフォーム:全Flutterプラットフォーム対応
2. インストール方法
pubspec.yaml
に以下を追加します:
dependencies:
flutter_md: ^0.0.5
インストール後に実行:
flutter pub get
3. 基本的な使い方
import 'package:flutter/material.dart';
import 'package:flutter_md/flutter_md.dart';
class MarkdownDisplayWidget extends StatelessWidget {
final String markdownContent = """# サンプルMarkdown
これは **太字** で、これは *斜体* です。
## リスト
- 項目1
- 項目2
- ネストした項目
- 項目3
## リンク
[Flutter公式サイト](https://flutter.dev)
> これは引用文です。複数行にわたって表示できます。
## コードサンプル
print('Hello, Markdown!');
""";
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Markdown表示')),
body: Padding(
padding: EdgeInsets.all(16.0),
child: MarkdownWidget(
markdown: Markdown.fromString(markdownContent),
),
),
);
}
}
4. テーマとカスタマイズ
基本的なテーマ設定
class CustomMarkdownWidget extends StatelessWidget {
final String markdownText;
CustomMarkdownWidget({required this.markdownText});
@override
Widget build(BuildContext context) {
return MarkdownTheme(
data: MarkdownThemeData(
textStyle: TextStyle(
fontSize: 16.0,
color: Colors.black87,
height: 1.6,
),
h1Style: TextStyle(
fontSize: 28.0,
fontWeight: FontWeight.bold,
color: Colors.blue.shade800,
),
h2Style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.bold,
color: Colors.blue.shade600,
),
quoteStyle: TextStyle(
fontSize: 14.0,
fontStyle: FontStyle.italic,
color: Colors.grey[600],
),
// リンククリック処理
onLinkTap: (title, url) {
print('リンクがタップされました: $title -> $url');
// URL起動やナビゲーション処理
},
),
child: MarkdownWidget(
markdown: Markdown.fromString(markdownText),
),
);
}
}
5. AI チャット風アプリでの活用
class ChatMessage extends StatelessWidget {
final String message;
final bool isUser;
ChatMessage({required this.message, required this.isUser});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!isUser) ...[
CircleAvatar(
backgroundColor: Colors.blue,
child: Icon(Icons.smart_toy, color: Colors.white),
),
SizedBox(width: 12),
],
Expanded(
child: Container(
padding: EdgeInsets.all(12.0),
decoration: BoxDecoration(
color: isUser ? Colors.blue.shade100 : Colors.grey.shade100,
borderRadius: BorderRadius.circular(12.0),
),
child: isUser
? Text(message, style: TextStyle(fontSize: 16.0))
: MarkdownTheme(
data: MarkdownThemeData(
textStyle: TextStyle(fontSize: 16.0),
h3Style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
// コードブロックの背景色設定
codeBlockDecoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(8.0),
),
),
child: MarkdownWidget(
markdown: Markdown.fromString(message),
),
),
),
),
if (isUser) ...[
SizedBox(width: 12),
CircleAvatar(
backgroundColor: Colors.green,
child: Icon(Icons.person, color: Colors.white),
),
],
],
),
);
}
}
6. パフォーマンス最適化
大きなMarkdownドキュメントや頻繁に変更されるコンテンツの場合:
class OptimizedMarkdownWidget extends StatefulWidget {
final String markdownContent;
OptimizedMarkdownWidget({required this.markdownContent});
@override
_OptimizedMarkdownWidgetState createState() => _OptimizedMarkdownWidgetState();
}
class _OptimizedMarkdownWidgetState extends State<OptimizedMarkdownWidget> {
late final Markdown _parsedMarkdown;
@override
void initState() {
super.initState();
// 初期化時に一度だけMarkdownを解析
_parsedMarkdown = Markdown.fromString(widget.markdownContent);
}
@override
Widget build(BuildContext context) {
return MarkdownWidget(markdown: _parsedMarkdown);
}
}
7. 高度なカスタマイズ
ブロックフィルタリング
MarkdownTheme(
data: MarkdownThemeData(
// 段落とヘッダーのみ表示
blockFilter: (block) {
return block is MD$Paragraph || block is MD$Heading;
},
// 画像とスポイラーを除外
spanFilter: (span) {
return !span.style.contains(MD$Style.image) &&
!span.style.contains(MD$Style.spoiler);
},
),
child: MarkdownWidget(markdown: parsedMarkdown),
)
カスタムスタイル処理
class AdvancedMarkdownWidget extends StatelessWidget {
final String markdownText;
AdvancedMarkdownWidget({required this.markdownText});
@override
Widget build(BuildContext context) {
return MarkdownTheme(
data: MarkdownThemeData(
textStyle: TextStyle(fontSize: 16.0),
// カスタムビルダー
builder: (block, theme) {
if (block is MD$Code && block.language == 'dart') {
return Container(
padding: EdgeInsets.all(12.0),
decoration: BoxDecoration(
color: Colors.blue.shade50,
border: Border.all(color: Colors.blue.shade200),
borderRadius: BorderRadius.circular(8.0),
),
child: Text(
block.text,
style: TextStyle(
fontFamily: 'monospace',
color: Colors.blue.shade800,
),
),
);
}
return null; // デフォルトのペインターを使用
},
),
child: MarkdownWidget(
markdown: Markdown.fromString(markdownText),
),
);
}
}
8. 対応しているMarkdown記法
記法 | サンプル | 説明 |
---|---|---|
太字 | **text** または __text__ | テキストを太字にする |
斜体 | *text* または _text_ | テキストを斜体にする |
取り消し線 | ~~text~~ | テキストに取り消し線を追加 |
インラインコード | `code` | インラインコードの表示 |
ハイライト | ==text== | テキストのハイライト |
スポイラー | ` | |
ヘッダー | # H1 ~ ###### H6 | 見出しレベル1-6 |
リスト | - item または 1. item | 順序なし・順序ありリスト |
引用 | > quote | 引用ブロック |
コードブロック | ```language | 構文ハイライト付きコード |
テーブル | ` | Col1 |
リンク | [text](url) | クリック可能リンク |
9. パフォーマンス指標
項目 | 性能 | 備考 |
---|---|---|
解析速度 | ~300μs | 典型的なAI応答の場合 |
他パッケージとの比較 | 15倍高速 | markdownパッケージ比 |
レンダリング | 120 FPS | チャット風インターフェース |
メモリ使用量 | 最小限 | 効率的なスパンフィルタリング |
10. 実用例:ドキュメントビューア
class DocumentViewer extends StatefulWidget {
@override
_DocumentViewerState createState() => _DocumentViewerState();
}
class _DocumentViewerState extends State<DocumentViewer> {
String documentContent = "";
@override
void initState() {
super.initState();
loadDocument();
}
Future<void> loadDocument() async {
// ドキュメントの読み込み(AssetやHTTP)
final content = await rootBundle.loadString('assets/document.md');
setState(() {
documentContent = content;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ドキュメント'),
actions: [
IconButton(
icon: Icon(Icons.share),
onPressed: () {
// 共有機能
},
),
],
),
body: documentContent.isEmpty
? Center(child: CircularProgressIndicator())
: SingleChildScrollView(
padding: EdgeInsets.all(16.0),
child: MarkdownTheme(
data: MarkdownThemeData(
textStyle: TextStyle(fontSize: 16.0, height: 1.6),
onLinkTap: (title, url) {
// URLを開く処理
print('Opening: $url');
},
),
child: MarkdownWidget(
markdown: Markdown.fromString(documentContent),
),
),
),
);
}
}
まとめ
特徴 | 内容 |
---|---|
高性能設計 | Flutter専用のカスタムレンダーオブジェクト使用 |
豊富なMarkdown対応 | 標準記法からスポイラーまで幅広くサポート |
完全カスタマイズ | テーマ、フィルター、カスタムビルダー対応 |
AI最適化 | ChatGPTやGeminiのコンテンツ表示に特化 |
クロスプラットフォーム | 全Flutter対応プラットフォームで動作 |
flutter_md
パッケージは、Flutter専用に最適化された高性能Markdownレンダラーとして、特にAI生成コンテンツの表示に威力を発揮します。 HTMLレンダリングやWebViewに依存せず、Flutterのレンダリングパイプラインに完全統合されているため、一貫したパフォーマンスと見た目を提供できます!
参考リンク