
FlutterでログUIを作ってみる
-
2023年8月22日
はじめに
こんにちは。エンジニアのSです。
今回はFlutterでツールアプリを開発するとき、情報を出力する際によくあるログUIの作り方を紹介したいと思います!
まず、ログUIっぽい簡単な文字表示のコードを書いてみます。
…
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(“<動作ログ>”),
Container(
width: 500,
height: 170,
color: const Color.fromARGB(255, 226, 226, 226),
child: SingleChildScrollView(
child: Text(
"Hello World\nHogeHogeHogeHogeHoge\nHogeHogeHogeHoge\nHogeHogeHoge",
style: TextStyle(fontSize: 35),
)
)),
],
),
…
はい、これで簡単に文字表示部分をスクロールできるようになりました!
文字を選択できるようにしたい
ですが、これだけではログにある文字を選択できないので、直感的にログ文字をコピーできないですね。
これは一般的に使われているTextクラスで、仕様上では選択できないからです。
選択できるようにしたいならば、SelectableTextクラスを置き換えるだけでできるようになります!
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(“<動作ログ>”),
Container(
width: 500,
height: 170,
color: const Color.fromARGB(255, 226, 226, 226),
child: SingleChildScrollView(
child: SelectableText(
"Hello World\nHogeHogeHogeHogeHoge\nHogeHogeHogeHoge\nHogeHogeHoge",
style: TextStyle(fontSize: 35),
)
)),
],
),
ログの種類によって文字のスタイルを変更したい
しかし、このままだとログUI内全部の文字スタイルが統一されてしまいます。
特定のログを別の色や太文字などで表示したい場合は、RichTextクラスを使うことをおすすめします。
RichTextはtextパラメータのタイプstringではなく、InlineSpanという別のクラスになっています。
具体的な書き方としては、スタイルの異なるテキストごとに、TextSpanクラスを作成してスタイルを設定し、最後にTextSpanクラスの配列をRichTextクラスのtextパラメータに入れることで、文字のスタイルを変更できます。
…
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(“<動作ログ>”),
Container(
width: 500,
height: 170,
color: const Color.fromARGB(255, 226, 226, 226),
child: SingleChildScrollView(
child: RichText(
text: TextSpan(children: [
TextSpan(text: "Hello World\n"),
TextSpan(
text: "HogeHogeHogeHoge\n",
style: TextStyle(
fontSize: 35,
color: Colors.red,
fontWeight: FontWeight.bold)),
TextSpan(
text: "HogeHogeHogeHoge\n",
style:
TextStyle(fontSize: 35, color: Colors.green)),
TextSpan(
text: "HogeHogeHogeHoge\n",
style: TextStyle(
fontSize: 35, color: Colors.yellow)),
]))
],
),
…
しかし、RichTextクラスでは文字の選択ができなくなります…
RichTextクラス公式ドキュメントによると、選択できるようにしたい場合は、SelectionAreaやSelectableRegionクラスを合わせて使う必要があると書いてありますが、もっと簡単な方法があります!
実はSelectableTextクラスには中身をRichTextとして出力するメソッドSelectableText.rich()がありますので、そちらを使うことで簡単にRichTextかつ文字選択ができるようになります!
…
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(“<動作ログ>”),
Container(
width: 500,
height: 170,
color: const Color.fromARGB(255, 226, 226, 226),
child: SingleChildScrollView(
child: SelectableText.rich(
TextSpan(children: [
TextSpan(text: "Hello World\n"),
TextSpan(
text: "HogeHogeHogeHoge\n",
style: TextStyle(
fontSize: 35,
color: Colors.red,
fontWeight: FontWeight.bold)),
TextSpan(
text: "HogeHogeHogeHoge\n",
style:
TextStyle(fontSize: 35, color: Colors.green)),
TextSpan(
text: "HogeHogeHogeHoge\n",
style: TextStyle(
fontSize: 35, color: Colors.yellow)),
]))
],
),
…
ログ出力メソッドを作る+コード整理
さて、UI表示はできましたので、次は実際に使うためのメソッド作成とコード整理について話します。
ログの種類のenumを作成します。
…
enum LogType {
unknown,
normal,
notice,
warning,
error;
}
…
そして、ログの変数を宣言します。
List<TextSpan> logText = []; //ログのテキスト
TextSpan _logTextSpan = const TextSpan(); //ログのUI
UI表示部分に変数を代入します。
…
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(“<動作ログ>”),
Container(
width: 500,
height: 170,
color: const Color.fromARGB(255, 226, 226, 226),
child: SingleChildScrollView(
child: SelectableText.rich(_logTextSpan),
)),
],
),
…
ログを出力してUIを更新するメソッドを作成します。
…
appendLog(String log, LogType logType) {
switch (logType) {
case LogType.normal:
logText.add(TextSpan(
text: "- $log\n", style: const TextStyle(color: Colors.black)));
break;
case LogType.notice:
logText.add(TextSpan(
text: "- $log\n",
style: const TextStyle(
color: Colors.black, fontWeight: FontWeight.bold)));
break;
case LogType.warning:
logText.add(TextSpan(
text: "- $log\n",
style: const TextStyle(color: Color.fromARGB(255, 154, 138, 0))));
break;
case LogType.error:
logText.add(TextSpan(
text: "- $log\n", style: const TextStyle(color: Colors.red)));
break;
default:
logText.add(TextSpan(text: "- $log\n"));
break;
}
// UIを更新する
setState(() {
_logTextSpan = TextSpan(children: List.from(logText));
});
}
}
…
はい!これでログテキストとログタイプを指定し、appendLog()メソッドを実行するだけで、すぐ指定されたスタイルのログを出力できるようになりました!
様々な実行やエラーログの出力をしてみましょう〜
最後に
UI更新部分ではsetStateを使っていますが、制限や更新時の描画にかかるコストなどの問題があると思います。
もっと大きめのアプリを開発する際は、BlocやProviderなどの状態管理手法で改善できると思いますが、今回は割愛させていただきます。
以上、FlutterでログUIを作ってみました!
ご参考になれば嬉しいです!