chat_page.dart 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import 'package:flutter/material.dart';
  2. import '../model/msg.dart';
  3. import '../util/ToastUtil.dart';
  4. import '../util/clipboard_util.dart';
  5. /// 聊天页面
  6. class ChatPage extends StatefulWidget {
  7. const ChatPage({super.key});
  8. @override
  9. State<StatefulWidget> createState() {
  10. return ChatPageState();
  11. }
  12. }
  13. class ChatPageState extends State<ChatPage> {
  14. /// TextField操作控制器
  15. final TextEditingController _editingController = TextEditingController();
  16. /// ListView的滚动控制器
  17. final ScrollController _scrollController = ScrollController();
  18. /// 输入框焦点
  19. final _inputFocusNode = FocusNode();
  20. /// 消息列表
  21. final List<Msg> _msgList = [];
  22. /// 添加消息到消息列表中
  23. void _addMsg2List(String msg, bool isMe) {
  24. setState(() {
  25. _msgList.add(
  26. Msg(isMe: isMe, msg: msg, createTime: DateTime.now().millisecond),
  27. );
  28. });
  29. Future.delayed(const Duration(milliseconds: 300), () {
  30. //延迟300毫秒,再滚动到列表底部
  31. _scrollController.jumpTo(_scrollController.position.maxScrollExtent);
  32. });
  33. }
  34. /// 发送消息
  35. void _sendMsg(String msg) {
  36. if (msg.isEmpty) {
  37. ToastUtil.showToast("请输入要发送的消息内容");
  38. return;
  39. }
  40. //添加消息到列表中
  41. _addMsg2List(msg, true);
  42. // 延迟生成对方的回复消息
  43. Future.delayed(const Duration(milliseconds: 150), () {
  44. //添加消息到列表中
  45. _addMsg2List(replyMessage2Client(msg), false);
  46. });
  47. //清除输入框的内容
  48. _editingController.clear();
  49. }
  50. /// 生成回复消息
  51. String replyMessage2Client(String clientMsg) {
  52. return clientMsg
  53. .replaceAll("我", "你")
  54. .replaceAll("吗", "")
  55. .replaceAll("?", "!")
  56. .replaceAll("?", "!");
  57. }
  58. /// 构建聊天气泡
  59. Widget _buildMsgBubble(Msg msg) {
  60. return Container(
  61. padding: const EdgeInsets.all(15.0),
  62. decoration: BoxDecoration(
  63. color:
  64. msg.isMe
  65. ? const Color.fromARGB(255, 164, 208, 238)
  66. : const Color.fromARGB(255, 153, 231, 169),
  67. borderRadius: BorderRadius.circular(12),
  68. ),
  69. // 消息文本
  70. child: Text(msg.msg),
  71. );
  72. }
  73. /// 构建聊天消息列表项
  74. Widget _buildMsgItem(Msg msg) {
  75. Widget content;
  76. // 自己发的
  77. if (msg.isMe) {
  78. content = Row(
  79. // 如果是自己发的,则在右边
  80. mainAxisAlignment: MainAxisAlignment.end,
  81. children: [
  82. // 聊天气泡
  83. _buildMsgBubble(msg),
  84. // 头像
  85. _buildAvatar(msg),
  86. ],
  87. );
  88. } else {
  89. // 对方发的
  90. content = Row(
  91. // 如果是自己发的,则在右边
  92. mainAxisAlignment: MainAxisAlignment.start,
  93. children: [
  94. // 头像
  95. _buildAvatar(msg),
  96. // 聊天气泡
  97. _buildMsgBubble(msg),
  98. ],
  99. );
  100. }
  101. return GestureDetector(
  102. onLongPress: () {
  103. // 长按消息,复制文本到剪切板
  104. ClipboardUtil.copyToClipboard(msg.msg);
  105. ToastUtil.showToast("已复制到剪切板");
  106. },
  107. child: Container(padding: const EdgeInsets.all(8.0), child: content),
  108. );
  109. }
  110. /// 构建头像
  111. Widget _buildAvatar(Msg msg) {
  112. return Container(
  113. margin: const EdgeInsets.symmetric(horizontal: 8.0),
  114. child: CircleAvatar(
  115. radius: 20,
  116. backgroundColor: Colors.grey,
  117. child: Text(
  118. msg.isMe ? "我" : "对方",
  119. style: const TextStyle(color: Colors.white),
  120. ),
  121. ),
  122. );
  123. }
  124. @override
  125. Widget build(BuildContext context) {
  126. return Scaffold(
  127. appBar: AppBar(
  128. leading: IconButton(
  129. onPressed: () {
  130. Navigator.pop(context, null);
  131. },
  132. icon: const Icon(Icons.arrow_back),
  133. ),
  134. title: const Text("聊天页"),
  135. ),
  136. body: Column(
  137. children: [
  138. Expanded(
  139. flex: 1,
  140. child: ListView.builder(
  141. controller: _scrollController,
  142. itemCount: _msgList.length,
  143. itemBuilder: (BuildContext context, int index) {
  144. return _buildMsgItem(_msgList[index]);
  145. },
  146. ),
  147. ),
  148. Center(
  149. child: Column(
  150. children: [
  151. Container(height: 0.3, color: Colors.grey),
  152. Padding(
  153. padding: const EdgeInsets.symmetric(
  154. vertical: 15.0,
  155. horizontal: 18.0,
  156. ),
  157. child: Row(
  158. mainAxisAlignment: MainAxisAlignment.start,
  159. children: [
  160. Expanded(
  161. flex: 1,
  162. child: TextField(
  163. // 设置按钮显示为发送
  164. textInputAction: TextInputAction.send,
  165. onSubmitted: (value) {
  166. // 用户点击软键盘的发送按钮
  167. var msg = _editingController.text;
  168. _sendMsg(msg);
  169. },
  170. // 输入框焦点
  171. focusNode: _inputFocusNode,
  172. // 点击外部区域,关闭软键盘
  173. onTapUpOutside: (event) {
  174. _inputFocusNode.unfocus();
  175. },
  176. controller: _editingController,
  177. decoration: const InputDecoration(
  178. //提示文字
  179. hintText: "请输入要发送的消息",
  180. //边框
  181. border: OutlineInputBorder(),
  182. ),
  183. ),
  184. ),
  185. Container(
  186. margin: const EdgeInsets.only(left: 5.0),
  187. child: ElevatedButton(
  188. child: const Text("发送"),
  189. onPressed: () {
  190. var msg = _editingController.text;
  191. _sendMsg(msg);
  192. },
  193. ),
  194. ),
  195. ],
  196. ),
  197. ),
  198. ],
  199. ),
  200. ),
  201. ],
  202. ),
  203. );
  204. }
  205. }