|
|
@@ -31,14 +31,29 @@ class ChatPageState extends State<ChatPage> {
|
|
|
@override
|
|
|
void initState() {
|
|
|
super.initState();
|
|
|
- _inputFocusNode.addListener(() {
|
|
|
- // 输入框获取焦点,滚动列表到底部
|
|
|
- _scrollToBottom();
|
|
|
- });
|
|
|
+ _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(() {
|
|
|
@@ -85,22 +100,34 @@ class ChatPageState extends State<ChatPage> {
|
|
|
|
|
|
/// 构建聊天气泡
|
|
|
Widget _buildMsgBubble(Msg msg) {
|
|
|
- return 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),
|
|
|
- backgroundColor:
|
|
|
- msg.isMe
|
|
|
- ? const Color.fromARGB(255, 164, 208, 238)
|
|
|
- : const Color.fromARGB(255, 153, 231, 169),
|
|
|
- contentBuilder: (context) {
|
|
|
- return Text(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);
|
|
|
+ },
|
|
|
+ ),
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -112,6 +139,8 @@ class ChatPageState extends State<ChatPage> {
|
|
|
content = Row(
|
|
|
// 如果是自己发的,则在右边
|
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
|
+ // 顶部对齐
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
children: [
|
|
|
// 聊天气泡
|
|
|
_buildMsgBubble(msg),
|
|
|
@@ -124,6 +153,8 @@ class ChatPageState extends State<ChatPage> {
|
|
|
content = Row(
|
|
|
// 如果是自己发的,则在右边
|
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
|
+ // 顶部对齐
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
children: [
|
|
|
// 头像
|
|
|
_buildAvatar(msg),
|
|
|
@@ -132,14 +163,15 @@ class ChatPageState extends State<ChatPage> {
|
|
|
],
|
|
|
);
|
|
|
}
|
|
|
- return GestureDetector(
|
|
|
- onLongPress: () {
|
|
|
- // 长按消息,复制文本到剪切板
|
|
|
- ClipboardUtil.copyToClipboard(msg.msg);
|
|
|
- ToastUtil.showToast("已复制到剪切板");
|
|
|
- },
|
|
|
- child: Container(padding: const EdgeInsets.all(8.0), child: content),
|
|
|
- );
|
|
|
+ // 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);
|
|
|
}
|
|
|
|
|
|
/// 构建头像
|