【Flutter】Flutter Chat UI(flutter_chat_ui)を使ってチャットアプリを最速で組み立てる方法【v2対応】
はじめに
Flutterでチャット機能を実装しようとすると、UIの構築やメッセージの管理が意外と手間に感じることがあります。
そんなときに便利なのが、flutter_chat_uiパッケージです。
公式パッケージページ(pub.dev)
2024年にリリースされたv2では、従来の使い方から大きな変更が加えられました。
この記事では、現在開発中のプロジェクトに導入している実装をベースに、flutter_chat_ui v2 の基本的な使い方と、カスタマイズの一例をご紹介します。
パッケージの導入
以下のコマンドで必要なパッケージを導入します。
flutter pub add flutter_chat_core
flutter pub add flutter_chat_ui
チャット画面の基本構成
ChatControllerを使ったメッセージ管理
v2からはChatControllerを通じてメッセージを管理するスタイルに変更されました。
final _chatController = InMemoryChatController();
Chatウィジェットのセットアップ
以下が、flutter_chat_uiのチャット画面構築の基本的なコードです。
メッセージ送信や添付ファイル選択、ユーザー情報の解決、カスタムUIの定義など、すべてChatウィジェットのプロパティとして指定できます。
Chat(
chatController: _chatController,
currentUserId: _myUserId,
onMessageSend: (text) {
final message = TextMessage(
id: uuid.v4(),
authorId: _myUserId,
createdAt: DateTime.now(),
text: text,
);
_chatController.insertMessage(message);
},
onAttachmentTap: () => _showAttachmentOptions(),
onMessageTap: (message) => _handleMessageTap(message),
resolveUser: (userId) async {
return User(id: userId, name: userId == _myUserId ? '自分' : '相手');
},
builders: Builders(...),
)
メッセージの送信方法
テキストメッセージの送信
final message = TextMessage(
id: uuid.v4(),
authorId: _myUserId,
createdAt: DateTime.now(),
text: 'こんにちは!',
);
_chatController.insertMessage(message);
画像やファイルメッセージの送信
画像の選択にはimage_picker、ファイルの選択にはfile_pickerを使用しています。
final image = await ImagePicker().pickImage(source: ImageSource.gallery);
if (image != null) {
final imageMessage = ImageMessage(
id: uuid.v4(),
authorId: _myUserId,
createdAt: DateTime.now(),
source: image.path,
);
_chatController.insertMessage(imageMessage);
}
final result = await FilePicker.platform.pickFiles();
if (result != null && result.files.single.path != null) {
final path = result.files.single.path!;
final fileMessage = FileMessage(
id: uuid.v4(),
authorId: _myUserId,
createdAt: DateTime.now(),
name: p.basename(path),
size: await File(path).length(),
source: path,
);
_chatController.insertMessage(fileMessage);
}
表示のカスタマイズ(Builders)
flutter_chat_uiはデフォルトでも十分使えるUIを提供していますが、プロダクトに合わせて自由にカスタマイズすることもできます。
ここでは、実際に行ったビルダーのカスタマイズ例をいくつかご紹介します。
テキストメッセージのバブル色を変更する
送信メッセージと受信メッセージで色を分けたい場合は、textMessageBuilderを使います。
textMessageBuilder: (context, message, index) {
return SimpleTextMessage(
message: message,
index: index,
showStatus: false,
showTime: false,
sentTextStyle: const TextStyle(color: Colors.black),
receivedTextStyle: const TextStyle(color: Colors.black),
sentBackgroundColor: Colors.lightBlueAccent.shade100,
receivedBackgroundColor: Colors.grey.shade200,
);
},
画像メッセージの表示をカスタムする
画像の角丸処理やエラー時の表示なども細かく調整できます。
imageMessageBuilder: (context, message, index) {
final isNetwork = message.source.startsWith('http');
final imageWidget = isNetwork
? Image.network(message.source, fit: BoxFit.cover, width: 160, height: 160)
: Image.file(File(message.source), fit: BoxFit.cover, width: 160, height: 160);
return Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: imageWidget,
),
);
},
ファイルメッセージの表示とタップ処理
ファイルメッセージの見た目や、タップ時の動作(保存など)も制御できます。
fileMessageBuilder: (context, message, index) {
return GestureDetector(
onTap: () => saveFile(message.source, message.name),
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.insert_drive_file, size: 24, color: Colors.blueGrey),
const SizedBox(width: 8),
Flexible(
child: Text(
message.name,
style: const TextStyle(fontSize: 14),
overflow: TextOverflow.ellipsis,
),
),
],
),
),
);
},
アバター・既読表示のカスタマイズ
メッセージの送信者に応じてアバターを出し分けたり、既読・未読表示も追加可能です。
以下は chatMessageBuilderの一例です:
chatMessageBuilder: (context, message, index, animation, child, {groupStatus, isRemoved}) {
final isSelf = message.authorId == _myUserId;
return Column(
crossAxisAlignment: isSelf ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
// 吹き出し
ChatMessage(
message: message,
index: index,
animation: animation,
groupStatus: groupStatus,
child: child,
),
// 既読・時間などの補助情報
Padding(
padding: const EdgeInsets.only(left: 4.0, right: 4.0, bottom: 4.0),
child: Row(
mainAxisAlignment: isSelf ? MainAxisAlignment.end : MainAxisAlignment.start,
children: [
if (isSelf)
Text(
message.seenAt != null ? '既読' : '未読',
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
const SizedBox(width: 6),
Text(
_formatTime(message.createdAt),
style: const TextStyle(fontSize: 11, color: Colors.grey),
),
],
),
),
],
);
},
v1からv2への変更点まとめ
| 項目 | v1 | v2 |
|---|---|---|
| メッセージ管理 | messagesに直接渡す | ChatController経由で操作 |
| イベントハンドラ | onSendPressed | onMessageSend に統一 |
| カスタマイズ方法 | theme, customMessageBuilder など | Builders に集約 |
| 型の扱い | やや曖昧(dynamicに近い) | TextMessage, ImageMessage など強化された型定義 |
おわりに
flutter_chat_uiは、比較的少ないコード量でモダンなチャットUIを構築できる便利なパッケージです。
特にv2では、ChatController を中心とした明確な設計になったことで、より柔軟で実用的なチャット画面が作りやすくなったと感じています。
本記事では、実際のプロジェクトで導入している構成をもとに、基本的な使い方と表示カスタマイズについてご紹介しました。
これからチャット機能を実装する方の参考になれば幸いです。
Discussion