import 'package:flutter/material.dart'; import '../model/msg.dart'; import '../util/ToastUtil.dart'; import '../util/clipboard_util.dart'; import '../widget/bubble/bubble_widget.dart'; /// 聊天页面 class ChatPage extends StatefulWidget { const ChatPage({super.key}); @override State createState() { return ChatPageState(); } } class ChatPageState extends State { /// TextField操作控制器 final TextEditingController _editingController = TextEditingController(); /// ListView的滚动控制器 final ScrollController _scrollController = ScrollController(); /// 输入框焦点 final _inputFocusNode = FocusNode(); /// 消息列表 final List _msgList = []; @override void initState() { super.initState(); _inputFocusNode.addListener(_handleTextFieldFocusChange); // 进入页面,就获取输入框焦点 _inputFocusNode.requestFocus(); } @override void dispose() { // 取消监听 _inputFocusNode.removeListener(_handleTextFieldFocusChange); _inputFocusNode.dispose(); _editingController.dispose(); _scrollController.dispose(); super.dispose(); } /// 处理输入框的焦点变化 void _handleTextFieldFocusChange() { if (_inputFocusNode.hasFocus) { // 输入框获取焦点,滚动列表到底部 _scrollToBottom(); } } /// 添加消息到消息列表中 void _addMsg2List(String msg, bool isMe) { setState(() { _msgList.add( Msg(isMe: isMe, msg: msg, createTime: DateTime.now().millisecond), ); }); _scrollToBottom(); } /// 滚动到列表底部 void _scrollToBottom() { //延迟300毫秒,再滚动到列表底部 Future.delayed(const Duration(milliseconds: 300), () { _scrollController.jumpTo(_scrollController.position.maxScrollExtent); }); } /// 发送消息 void _sendMsg(String msg) { if (msg.isEmpty) { ToastUtil.showToast("请输入要发送的消息内容"); return; } //添加消息到列表中 _addMsg2List(msg, true); // 延迟生成对方的回复消息 Future.delayed(const Duration(milliseconds: 150), () { //添加消息到列表中 _addMsg2List(replyMessage2Client(msg), false); }); //清除输入框的内容 _editingController.clear(); } /// 生成回复消息 String replyMessage2Client(String clientMsg) { return clientMsg .replaceAll("我", "你") .replaceAll("吗", "") .replaceAll("?", "!") .replaceAll("?", "!"); } /// 构建聊天气泡 Widget _buildMsgBubble(Msg msg) { // 设置气泡的外边距,让气泡不易过长 double marginValue = 50; EdgeInsets marginEdgeInsets; if (msg.isMe) { marginEdgeInsets = EdgeInsets.only(left: marginValue); } else { marginEdgeInsets = EdgeInsets.only(right: marginValue); } // Flexible,文本超过一行时,自动换行,并且不超过最大宽度,不超过一行时,则自动包裹内容 return Flexible( child: BubbleWidget( // 箭头方向 arrowDirection: msg.isMe ? AxisDirection.right : AxisDirection.left, arrowOffset: 22, arrowLength: 8, arrowRadius: 4, arrowWidth: 14, padding: const EdgeInsets.all(12), borderRadius: BorderRadius.circular(8), margin: marginEdgeInsets, backgroundColor: msg.isMe ? const Color.fromARGB(255, 164, 208, 238) : const Color.fromARGB(255, 153, 231, 169), contentBuilder: (context) { return SelectableText(msg.msg); }, ), ); } /// 构建聊天消息列表项 Widget _buildMsgItem(Msg msg) { Widget content; // 自己发的 if (msg.isMe) { content = Row( // 如果是自己发的,则在右边 mainAxisAlignment: MainAxisAlignment.end, // 顶部对齐 crossAxisAlignment: CrossAxisAlignment.start, children: [ // 聊天气泡 _buildMsgBubble(msg), // 头像 _buildAvatar(msg), ], ); } else { // 对方发的 content = Row( // 如果是自己发的,则在右边 mainAxisAlignment: MainAxisAlignment.start, // 顶部对齐 crossAxisAlignment: CrossAxisAlignment.start, children: [ // 头像 _buildAvatar(msg), // 聊天气泡 _buildMsgBubble(msg), ], ); } // return GestureDetector( // onLongPress: () { // // 长按消息,复制文本到剪切板 // ClipboardUtil.copyToClipboard(msg.msg); // ToastUtil.showToast("已复制到剪切板"); // }, // child: Container(padding: const EdgeInsets.all(8.0), child: content), // ); return Container(padding: const EdgeInsets.all(8.0), child: content); } /// 构建头像 Widget _buildAvatar(Msg msg) { return Container( margin: const EdgeInsets.symmetric(horizontal: 8.0), child: CircleAvatar( radius: 20, backgroundColor: Colors.grey, child: Text( msg.isMe ? "我" : "对方", style: const TextStyle(color: Colors.white), ), ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading: IconButton( onPressed: () { Navigator.pop(context, null); }, icon: const Icon(Icons.arrow_back), ), title: const Text("聊天页"), ), body: Column( children: [ Expanded( flex: 1, child: ListView.builder( controller: _scrollController, itemCount: _msgList.length, itemBuilder: (BuildContext context, int index) { return _buildMsgItem(_msgList[index]); }, ), ), Center( child: Column( children: [ Container(height: 0.3, color: Colors.grey), Padding( padding: const EdgeInsets.symmetric( vertical: 15.0, horizontal: 18.0, ), child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Expanded( flex: 1, child: TextField( // 设置按钮显示为发送 textInputAction: TextInputAction.send, onSubmitted: (value) { // 用户点击软键盘的发送按钮 var msg = _editingController.text; _sendMsg(msg); }, // 输入框焦点 focusNode: _inputFocusNode, // 点击外部区域,关闭软键盘 onTapUpOutside: (event) { _inputFocusNode.unfocus(); }, controller: _editingController, decoration: const InputDecoration( //提示文字 hintText: "选择粘贴TA的话,选择人设风格回复", //边框 border: OutlineInputBorder(), ), ), ), Container( margin: const EdgeInsets.only(left: 15.0), child: ElevatedButton( child: const Text("发送"), onPressed: () { var msg = _editingController.text; _sendMsg(msg); }, ), ), ], ), ), ], ), ), ], ), ); } }