这篇文章主要讲解了“flutter微信聊天输入框功能如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“flutter微信聊天输入框功能如何实现”吧!
高仿微信聊天输入框,效果图如下(目前都是静态展示,服务还没开始开发):
大家如果观察仔细的话 应该会发现,他输入框下面的高度 刚好就是 软键盘的高度;所以在这里就需要监听软键盘的高度。还要配置
resizeToAvoidBottomInset: false,
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
这里以 单聊为例:
遇到有个问题就是输入框行数的限制:这里这只 maxLines:null,就能自适应高度了。
就能做到 TextField多行输入了
child: TextField(
// maxLength: maxLength,
focusNode: focusNode,
maxLines: null,
maxLength: 200,
cursorColor: AppColor.color3BAB71,
controller: controller,
textAlignVertical: TextAlignVertical.center,
keyboardType: keyboardType,
onEditingComplete: onEditingComplete,
onSubmitted: onSubmitted,
style: style ?? AppTextStyle.textStyle_28_333333,
// inputFormatters: inputFormatters,
decoration: InputDecoration(
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(width: 0, color: Colors.transparent)),
disabledBorder: const OutlineInputBorder(
borderSide: BorderSide(width: 0, color: Colors.transparent)),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(width: 0, color: Colors.transparent)),
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(7.cale),
//borderSide: BorderSide(width: 0, color: Colors.transparent),
// borderSide: BorderSide(width: 0, color: Colors.transparent),
),
hintText: hintText,
prefixIcon: prefixIcon,
prefixIconConstraints: prefixIconConstraints,
hintStyle: hintStyle ?? AppTextStyle.textStyle_28_AAAAAA,
counterText: '', //取消文字计数器
// border: InputBorder.none,
isDense: true,
errorText: errorText,
contentPadding: EdgeInsets.symmetric(
horizontal: 16.cale,
vertical: 20.cale,
),
),
// contentPadding:
// EdgeInsets.only(left: 16.cale, right: 16.cale, top: 20.cale),
// errorText: "输入错误",
),
代码结构如下:
--- chatCommon
------ chat_bottom.dart 聊天底部输入框
------ chat_element_other.dart 聊天时别人信息的显示
------ chat_element_self.dart 聊天时自己信息的显示
------ chat_input_box.dart 聊天文本输入框封装
------ page_chat_group.dart 群聊
------ page_chat_person.dart 单聊
------ provider_chat_content.dart 聊天键盘显示 事件的传递 /键盘高度的处理
chat_bottom.dart
import 'package:flutter/material.dart';
import 'package:imflutter/const/app_textStyle.dart';
import 'package:imflutter/pages/chatCommon/provider_chat_content.dart';
import 'package:imflutter/wrap/extension/extension.dart';
import '../../const/app_colors.dart';
import '../../const/app_icon.dart';
import '../../wrap/widget/app_widget.dart';
import 'chat_input_box.dart';
class ChatBottom extends StatefulWidget {
final ProviderChatContent providerChatContent;
const ChatBottom({Key? key, required this.providerChatContent})
: super(key: key);
State<ChatBottom> createState() => _ChatBottomState();
}
class _ChatBottomState extends State<ChatBottom> with WidgetsBindingObserver {
// 0 语音 1 键盘 2 表情
int _inputType = 0;
final TextEditingController _controller = TextEditingController();
final FocusNode _focusNode = FocusNode();
bool get _keyboardShow => widget.providerChatContent.contentShow;
final List<Map> _listOption = [
{'title': '相册', 'icon': 'assets/common/chat/ic_details_photo.webp'},
{'title': '拍照', 'icon': 'assets/common/chat/ic_details_camera.webp'},
{'title': '视频通话', 'icon': 'assets/common/chat/ic_details_video.webp'},
{'title': '位置', 'icon': 'assets/common/chat/ic_details_localtion.webp'},
{'title': '红包', 'icon': 'assets/common/chat/ic_details_red.webp'},
{'title': '转账', 'icon': 'assets/common/chat/ic_details_transfer.webp'},
{'title': '语音输入', 'icon': 'assets/common/chat/ic_chat_voice.webp'},
{'title': '我的收藏', 'icon': 'assets/common/chat/ic_details_favorite.webp'},
];
@override
void initState() {
// TODO: implement initState
super.initState();
WidgetsBinding.instance.addObserver(this);
_controller.addListener(() {
setState(() {});
});
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
widget.providerChatContent.updateContentShow(true);
}
});
}
@override
Widget build(BuildContext context) {
print('ChatBottom------------------------build');
return Container(
padding: EdgeInsets.symmetric(vertical: 20.cale),
decoration: BoxDecoration(
color: AppColor.colorF7F7F7,
border: Border(
top: BorderSide(width: 1.cale, color: AppColor.colordddddd),
),
),
// height: 110.cale,
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 20),
transitionBuilder: (Widget child, Animation<double> animation) {
return FadeTransition(
opacity: animation,
child: child,
);
},
child: _inputType == 0
? AppWidget.inkWellEffectNone(
key: const ValueKey("AppIcon.audio"),
onTap: () {
print('启动音频');
_inputType = 1;
widget.providerChatContent.updateContentShow(false);
},
child: Padding(
padding:
EdgeInsets.only(left: 20.cale, bottom: 15.cale),
child: Icon(
AppIcon.audio,
size: 50.cale,
color: Colors.black,
),
),
)
: AppWidget.inkWellEffectNone(
key: const ValueKey("AppIcon.keyboard"),
onTap: () {
_inputType = 0;
widget.providerChatContent.updateContentShow(true);
_focusNode.requestFocus();
},
child: Padding(
padding:
EdgeInsets.only(left: 20.cale, bottom: 15.cale),
child: Icon(
AppIcon.keyboard,
size: 50.cale,
color: Colors.black,
),
),
),
),
Expanded(
child: _inputType == 0
? Padding(
padding: EdgeInsets.symmetric(
horizontal: 20.cale,
),
child: ChatInputBox(
style: AppTextStyle.textStyle_30_000000,
onEditingComplete: () {
print("onEditingComplete");
},
onSubmitted: (str) {
print("onSubmitted:$str");
},
controller: _controller,
focusNode: _focusNode,
),
)
: AppWidget.inkWellEffectNone(
onTap: () {},
child: Container(
margin: EdgeInsets.symmetric(horizontal: 20.cale),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(7.cale),
),
height: 80.cale,
child: Center(
child: Text(
'按住 说话',
style: AppTextStyle.textStyle_30_000000,
),
),
),
),
),
AppWidget.inkWellEffectNone(
onTap: () {
print('添加表情符号');
},
child: Padding(
padding: EdgeInsets.only(bottom: 15.cale),
child: Icon(
AppIcon.faceHappy,
size: 50.cale,
color: Colors.black,
),
),
),
AnimatedSwitcher(
duration: const Duration(milliseconds: 50),
transitionBuilder: (Widget child, Animation<double> animation) {
return ScaleTransition(
scale: animation,
alignment: Alignment.centerRight,
child: FadeTransition(
opacity: animation,
child: child,
),
);
},
child: _inputType == 0 && _controller.value.text.isNotEmpty
? AppWidget.inkWellEffectNone(
key: const ValueKey('发送'),
onTap: () {
print('发送');
_controller.clear();
},
child: Container(
margin: EdgeInsets.only(
left: 20.cale, right: 24.cale, bottom: 10.cale),
padding: EdgeInsets.symmetric(
horizontal: 24.cale,
vertical: 10.cale,
),
decoration: BoxDecoration(
color: AppColor.color05C160,
borderRadius: BorderRadius.circular(12.cale),
),
child: Center(
child: Text(
'发送',
style: AppTextStyle.textStyle_30_FFFFFF,
)),
),
)
: AppWidget.inkWellEffectNone(
key: const ValueKey('AppIcon.add'),
onTap: () {
print('添加附件 图片视频');
setState(() {
if (_focusNode.hasFocus) {
_focusNode.unfocus();
}
widget.providerChatContent.updateContentShow(true);
// print(
// '---------${DataInheritedWidget.of(context)?.dataEnvironment.keyboardHeight}');
//InheritedKeyboard.of(context)?.updateKeyboard(true);
});
},
child: Padding(
padding: EdgeInsets.only(
left: 10.cale, right: 20.cale, bottom: 10.cale),
child: Icon(
AppIcon.add,
size: 58.cale,
color: Colors.black,
),
),
),
),
],
),
if (_keyboardShow)
Container(
width: double.infinity,
margin: EdgeInsets.only(
top: 20.cale,
),
// padding: EdgeInsets.only(bottom: 200.cale),
decoration: BoxDecoration(
border: Border(
top: BorderSide(width: 1.cale, color: AppColor.colordddddd),
),
),
height: widget.providerChatContent.keyboardHeight,
child: Wrap(
runAlignment: WrapAlignment.center,
alignment: WrapAlignment.center,
//crossAxisAlignment: WrapCrossAlignment.center,
spacing: 75.cale,
runSpacing: 60.cale,
children: _listOption
.asMap()
.map(
(key, value) => MapEntry(
key,
SizedBox(
width: 100.cale,
height: 150.cale,
child: Column(
children: [
Container(
width: 100.cale,
height: 100.cale,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(25.cale),
),
child: Image.asset(
value['icon'],
w