見出し画像

Flutter Webでリッチテキストエディタを作成してみた。


はじめに

この記事は、私の調べ方が悪いのか、記事が少ないと感じたので、タイトルの通り、Flutter Webでリッチテキストを作成した際の私が行った方法をFlutter初心者なりに書いたものになります。
あまり詳しく記載できませんが、少しでも参考になれば幸いです。

リッチテキストとリッチテキストエディタとは

リッチテキストとは

リッチテキスト(richtext)とは、マイクロソフトが決めた文書ファイルの形式で、文字が並ぶだけのテキスト形式に、文字のサイズや太さ、取り消し線などの簡単なレイアウト情報を追加したものです。

テキスト形式の入力欄
リッチテキスト形式の入力欄

画像のように、リッチテキスト形式にすることによって、いろいろな修飾ができるようになります。

リッチテキストエディタとは

名前の通り、リッチテキスト形式のファイルを編集する時に使用するソフトです。

noteで出てくる編集バー

↑の画像の中の項目から選んで文字を修飾できます。
インターネットで「flutter  リッチテキストエディタ」と検索すると、flutter_quillやzefyrなるものがあるようです。
サイトによっては、zefyrはやめた方がいいという意見があるみたいです。

実際に作成してみた。

今回、私がリッチテキスト形式の入力欄を作成するにあたって使用したものが、テーマの通り「Flutter_quill」というリッチテキストエディタです。
画面遷移して表示するまでのコードまでになります。

Flutter_quillを使用するには

Flutter_quillを使用するには、まず、依存関係を追加する必要があるので、「pubspec.yaml」ファイルに追加しましょう。

ファイルを追加したら、ターミナルでflutter pub getを実行します。
これで準備が整いました!!
(バージョンによって動作しない場合があります。)

リッチテキストエディタを作成する

依存関係を追加したので、使用するためにリッチテキストエディタを含むFlutter ウィジェットを作成します。

import 'package:flutter_quill/flutter_quill.dart' as quill;

私が使用した時は、一緒にコードに書いていたTextウィジェットと競合したので、接頭辞をつけています。
下記が全体のコードになります。

import 'package:flutter/material.dart';
import 'package:flutter_application_note/nextPage.dart';
import 'package:flutter_quill/flutter_quill.dart' as quill;

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late FocusNode _focusNode;
  final quill.QuillController _controller = quill.QuillController.basic();

  @override
  void initState() {
    super.initState();
    _focusNode = FocusNode();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      FocusScope.of(context).requestFocus(_focusNode);
    });
  }

  @override
  void dispose() {
    _focusNode.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(children: [
          const SizedBox(
            height: 40,
          ),
          Container(
            width: 400,
            height: 240,
            decoration: BoxDecoration(
              border: Border.all(
                color: const Color.fromARGB(255, 198, 198, 198),
                width: 3,
              ),
              borderRadius: BorderRadius.circular(5),
            ),
            child: Column(
              children: [
                quill.QuillToolbar.basic(
                  controller: _controller,
                  showItalicButton: false,
                  showHeaderStyle: false,
                  showUnderLineButton: false,
                  showListCheck: false,
                  showListNumbers: false,
                  showListBullets: false,
                  showIndent: false,
                  showRedo: false,
                  showUndo: false,
                  showSubscript: false,
                  showSearchButton: false,
                  showSuperscript: false,
                  showStrikeThrough: false,
                  showInlineCode: false,
                  showFontFamily: false,
                  showClearFormat: false,
                  showCodeBlock: false,
                  showQuote: false,
                  showBackgroundColorButton: false,
                ),
                Expanded(
                  child: quill.QuillEditor(
                    controller: _controller,
                    focusNode: _focusNode,
                    scrollController: ScrollController(),
                    scrollable: true,
                    padding: const EdgeInsets.all(16.0),
                    autoFocus: false,
                    expands: false,
                    readOnly: false,
                  ),
                ),
              ],
            ),
          ),
          ElevatedButton(
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => NextPage(
                    data: _controller.document.toDelta(),
                  ),
                ),
              );
            },
            child: const Text('次へ'),
          )
        ]),
      ),
    );
  }
}

バージョンによって変わりますが、今回使ったFlutter_quillのbasicというのを使用すると、すごい量の修飾ボタンが表示されます。なので、「quill.QuillToolBar.basic」の中で、

showItaricButton: false,

と記載し、不要だと思う修飾ボタンを非表示にしています。
このコードで実行すると

このような表示になります。

ノーマル、太字、大きめ、色変えで、入力しました。

リッチテキストのデータの引き渡し・取得・表示

次に、画面遷移をして表示してみます。

data: _controller.document.toDelta(),

また、画面遷移の際は、入力された内容をデルタ型に変え引数dataに格納し渡しています。

画面遷移先の画面のコードはこちらです。

// ignore_for_file: file_names
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' as quill;

class NextPage extends StatelessWidget {
  final quill.Delta data;
  const NextPage({super.key, required this.data});

  @override
  Widget build(BuildContext context) {
    final quillController = quill.QuillController(
      document: quill.Document.fromDelta(data),
      selection: const TextSelection.collapsed(offset: 0),
    );
    return Scaffold(
      appBar: AppBar(
        title: const Text('画面遷移確認ページ'),
      ),
      body: Center(
          child: SizedBox(
        width: 400,
        height: 240,
        child: quill.QuillEditor(
          controller: quillController,
          readOnly: true,
          focusNode: FocusNode(),
          scrollController: ScrollController(),
          scrollable: false,
          padding: EdgeInsets.zero,
          autoFocus: false,
          expands: false,
        ),
      )),
    );
  }
}

ここで注意して欲しいのが、デルタ型のデータを受け取っても、画面遷移先でもQuillControllerを使用しないと修飾情報が適用されないです。

無事に修飾した内容を表示できました!
(確認用なので、レイアウトテキトーなの許してください。。。)


表示だけにしたい場合は、QuillControllerの設定のreadOnlyの項目を、trueすることで、編集ができなくなります。
また、autoFocusをtrueにすると、そのページを表示したときにすぐに入力できるようになります。

まとめ

今回はFlutterWebでリッチテキストエディタを作成してみました。
私のように、Flutterでリッチテキストエディタ使いたいけど公式とかじゃ分からない方々の助けになれば嬉しいです。(そもそも私は、リッチテキストの名前すら知らなかったけど。。。)

Flutter は比較的新しい言語なので、もっと多くの人に知ってもらい、記事が増え、技術が進歩すれば嬉しく思います。
最後まで読んでいただき、ありがとうございました!

この記事が気に入ったらサポートをしてみませんか?