高仿微信聊天输入框,效果图如下(目前都是静态展示,服务还没开始开发):
大家如果观察仔细的话 应该会发现,他输入框下面的高度 刚好就是 软键盘的高度;所以在这里就需要监听软键盘的高度。还要配置
resizeToAvoidBottomInset: false, return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar(
(因为严格限制 gif动图大小(600kb左右) 无奈只能压缩 所以很糊)(第二张动图 是github上的不知道能放多久)
这里以 单聊为例:
遇到有个问题就是输入框行数的限制:这里这只 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'], width: 50.cale, height: 50.cale, ), ), Padding( padding: EdgeInsets.only(top: 16.cale), child: Text( value['title'], style: AppTextStyle.textStyle_20_656565, ), ) ], ), ), ), ) .values .toList(), ), ) ], ), ); } ///应用尺寸改变时回调,例如旋转 键盘 @override void didChangeMetrics() { // TODO: implement didChangeMetrics super.didChangeMetrics(); if (mounted) { // 键盘高度 final double viewInsetsBottom = EdgeInsets.fromWindowPadding( WidgetsBinding.instance.window.viewInsets, WidgetsBinding.instance.window.devicePixelRatio) .bottom; if (viewInsetsBottom > 0) { widget.providerChatContent.updateKeyboardHeight(viewInsetsBottom); } } } @override void dispose() { // TODO: implement dispose _focusNode.dispose(); _controller.dispose(); WidgetsBinding.instance.removeObserver(this); super.dispose(); } }
chat_element_other.dart
import 'package:flutter/material.dart'; import 'package:imflutter/const/app_colors.dart'; import 'package:imflutter/wrap/extension/extension.dart'; import 'package:imflutter/wrap/widget/app_widget.dart'; class ChatElementOther extends StatefulWidget { /// 用户信息 final Map userInfo; /// 消息 final Map chatMessage; const ChatElementOther( {Key? key, required this.userInfo, required this.chatMessage}) : super(key: key); @override State<ChatElementOther> createState() => _ChatElementOtherState(); } class _ChatElementOtherState extends State<ChatElementOther> { @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.only(top: 24.cale), child: Column( children: [ Padding( padding: EdgeInsets.only(bottom: 40.cale), child: Text('11:25'), ), Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.only(left: 24.cale), child: AppWidget.inkWellEffectNone( onTap: () {}, child: ClipRRect( borderRadius: BorderRadius.circular(7.cale), child: AppWidget.cachedImage(widget.userInfo['icon'], width: 75.cale, height: 75.cale), ), ), ), _chatContent(), ], ) ], ), ); } Widget _chatContent() { /// 1 文本 /// 2 图片 /// 3 语音 /// 4 视频 /// 5 提示消息 /// 6 提示消息 switch (widget.chatMessage['type']) { case 1: return _chatType1(); break; case 2: return _chatType2(); break; case 3: return _chatType3(); break; case 4: return _chatType4(); break; case 5: return _chatType5(); break; case 6: return _chatType6(); break; default: return Container(); break; } } Widget _chatType1() { return Stack( children: [ Container( margin: EdgeInsets.only(left: 25.cale), constraints: BoxConstraints(maxWidth: 500.cale), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12.cale), ), padding: EdgeInsets.symmetric( vertical: 18.cale, horizontal: 20.cale, ), child: Text( widget.chatMessage['content_1'], softWrap: true, ), ), Positioned( top: 25.cale, left: 10.cale, child: CustomPaint( size: Size(20.cale, 30.cale), painter: TrianglePainter(), ), ), ], ); } Widget _chatType2() { return Container( constraints: BoxConstraints( maxWidth: 320.cale, maxHeight: 300.cale, minHeight: 120.cale, ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(7.cale), border: Border.all(width: 1.cale / 2, color: AppColor.color636363), ), margin: EdgeInsets.only(left: 20.cale), child: ClipRRect( borderRadius: BorderRadius.circular(7.cale), child: AppWidget.cachedImage( widget.chatMessage['content_2']['picture_mini']['url'], ), ), ); } Widget _chatType3() { return Container( color: Colors.white, padding: EdgeInsets.all(18.cale), child: Text("这是语音"), ); } Widget _chatType4() { return Container( color: Colors.white, padding: EdgeInsets.all(18.cale), child: Text("这是视频"), ); } Widget _chatType5() { return Container( color: Colors.white, padding: EdgeInsets.all(18.cale), child: Text("这是提示5"), ); } Widget _chatType6() { return Container( color: Colors.white, padding: EdgeInsets.all(18.cale), child: Text("这是提示6"), ); } } class TrianglePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { Paint paint = Paint()..color = Colors.white; Path path = Path(); path.moveTo(0, size.height / 2); path.lineTo(size.width, 0); path.lineTo(size.width, size.height); path.close(); canvas.drawPath(path, paint); return; } @override bool shouldRepaint(covariant CustomPainter oldDelegate) { // TODO: implement shouldRepaint return false; } }
chat_element_self.dart
import 'package:flutter/material.dart'; import 'package:imflutter/const/app_colors.dart'; import 'package:imflutter/wrap/extension/extension.dart'; import 'package:imflutter/wrap/widget/app_widget.dart'; class ChatElementSelf extends StatefulWidget { /// 用户信息 final Map userInfo; /// 消息 final Map chatMessage; const ChatElementSelf( {Key? key, required this.userInfo, required this.chatMessage}) : super(key: key); @override State<ChatElementSelf> createState() => _ChatElementSelfState(); } class _ChatElementSelfState extends State<ChatElementSelf> { @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.only(top: 24.cale), child: Column( children: [ Padding( padding: EdgeInsets.only(bottom: 40.cale), child: Text('11:25'), ), Row( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.start, children: [ _chatContent(), Padding( padding: EdgeInsets.only(right: 24.cale), child: AppWidget.inkWellEffectNone( onTap: () {}, child: ClipRRect( borderRadius: BorderRadius.circular(7.cale), child: AppWidget.cachedImage(widget.userInfo['icon'], width: 75.cale, height: 75.cale), ), ), ), ], ) ], ), ); } Widget _chatContent() { /// 1 文本 /// 2 图片 /// 3 语音 /// 4 视频 /// 5 提示消息 /// 6 提示消息 switch (widget.chatMessage['type']) { case 1: return _chatType1(); break; case 2: return _chatType2(); break; case 3: return _chatType3(); break; case 4: return _chatType4(); break; case 5: return _chatType5(); break; case 6: return _chatType6(); break; default: return Container(); break; } } Widget _chatType1() { return Stack( children: [ Container( margin: EdgeInsets.only(right: 25.cale), constraints: BoxConstraints(maxWidth: 500.cale), decoration: BoxDecoration( color: AppColor.color94ED6D, borderRadius: BorderRadius.circular(12.cale), ), padding: EdgeInsets.symmetric( vertical: 18.cale, horizontal: 20.cale, ), child: Text( widget.chatMessage['content_1'], softWrap: true, ), ), Positioned( top: 25.cale, right: 10.cale, child: CustomPaint( size: Size(20.cale, 30.cale), painter: TrianglePainter(), ), ), ], ); } Widget _chatType2() { return Container( constraints: BoxConstraints( maxWidth: 320.cale, maxHeight: 300.cale, minHeight: 120.cale, ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(7.cale), border: Border.all(width: 1.cale / 2, color: AppColor.color636363), ), margin: EdgeInsets.only(right: 20.cale), child: ClipRRect( borderRadius: BorderRadius.circular(7.cale), child: AppWidget.cachedImage( widget.chatMessage['content_2']['picture_mini']['url'], ), ), ); } Widget _chatType3() { return Container( color: Colors.white, padding: EdgeInsets.all(18.cale), child: Text("这是语音"), ); } Widget _chatType4() { return Container( color: Colors.white, padding: EdgeInsets.all(18.cale), child: Text("这是视频"), ); } Widget _chatType5() { return Container( color: Colors.white, padding: EdgeInsets.all(18.cale), child: Text("这是提示5"), ); } Widget _chatType6() { return Container( color: Colors.white, padding: EdgeInsets.all(18.cale), child: Text("这是提示6"), ); } } class TrianglePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { Paint paint = Paint()..color = AppColor.color94ED6D; Path path = Path(); // path.moveTo(0, 0); // path.lineTo(0, size.height); // path.lineTo(size.width, size.height); // path.lineTo(size.width, 0); path.moveTo(0, 0); path.lineTo(0, size.height); path.lineTo(size.width, size.height / 2); path.close(); canvas.drawPath(path, paint); return; } @override bool shouldRepaint(covariant CustomPainter oldDelegate) { // TODO: implement shouldRepaint return false; } }
chat_input_box.dart
import 'package:flutter/material.dart'; import 'package:imflutter/const/app_colors.dart'; import 'package:imflutter/wrap/extension/extension.dart'; import '../../const/app_textStyle.dart'; class ChatInputBox extends StatelessWidget { final String? hintText; final int? maxLength; final VoidCallback? onEditingComplete; final ValueChanged<String>? onSubmitted; final EdgeInsetsGeometry? contentPadding; final TextEditingController? controller; final String? errorText; final Widget? prefixIcon; final TextInputType? keyboardType; final BoxConstraints? prefixIconConstraints; final BoxDecoration? decoration; final TextStyle? style; final TextStyle? hintStyle; final FocusNode? focusNode; const ChatInputBox({ Key? key, this.maxLength = 20, this.controller, this.errorText, this.prefixIcon, this.prefixIconConstraints, this.onEditingComplete, this.onSubmitted, this.contentPadding = EdgeInsets.zero, this.decoration, this.keyboardType, this.style, this.hintStyle, this.focusNode, this.hintText, }) : super(key: key); @override Widget build(BuildContext context) { return Container( // height: 75.cale, // margin: EdgeInsets.all(5.cale), constraints: BoxConstraints( minHeight: 75.cale, maxHeight: 350.cale, ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(7.cale), color: Colors.white, ), 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: "输入错误", ), ); } }
page_chat_person.dart
import 'package:flutter/material.dart'; import 'package:imflutter/wrap/extension/extension.dart'; import 'package:imflutter/wrap/navigator/app_navigator.dart'; import 'package:imflutter/pages/chatCommon/chat_element_other.dart'; import 'package:provider/provider.dart'; import '../../const/app_colors.dart'; import '../../const/app_icon.dart'; import '../../const/app_textStyle.dart'; import '../../wrap/widget/app_widget.dart'; import 'provider_chat_content.dart'; import 'chat_bottom.dart'; import 'chat_element_self.dart'; class PageChatPerson extends StatefulWidget { final Map userInfoOther; const PageChatPerson({Key? key, required this.userInfoOther}) : super(key: key); @override State<PageChatPerson> createState() => _PageChatPersonState(); } class _PageChatPersonState extends State<PageChatPerson> { /// 1 文本 /// 2 图片 /// 3 语音 /// 4 视频 /// 5 提示消息 /// 6 提示消息 final List<Map> _arrayChatMessage = []; @override void initState() { // TODO: implement initState super.initState(); // for (int i = 13; i >= 0; i--) { // //_arrayChatMessage.addAll(_cache); // print("------------------i % 6 + 1:${i % 6 + 1}"); // _arrayChatMessage.add({ // 'id': i, // 'type': i % 6 + 1, // 'content_1': '你吃饭了吗2${i}-${i % 6}', // 'content_2': { // 'picture_mini': { // 'url': // 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', // 'width': 450, // 'height': 200 // }, // 'picture': // 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', // }, // 'content_3': // 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', // 'content_4': '', // 'content_5': '', // 'content_6': '', // 'times': 1000000 + i // }); // } _arrayChatMessage.add({ 'id': 99, 'type': 1, 'content_1': '你吃饭了吗? ', 'content_2': { 'picture_mini': { 'url': 'https://img2.baidu.com/it/u=3202947311,1179654885&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500', 'width': 800, 'height': 500 }, 'picture': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', }, 'content_3': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', 'content_4': '', 'content_5': '', 'content_6': '', 'times': 1000000 + 9 }); _arrayChatMessage.add({ 'id': 100, 'type': 1, 'content_1': '我吃过了你呢? ', 'content_2': { 'picture_mini': { 'url': 'https://img2.baidu.com/it/u=3202947311,1179654885&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500', 'width': 800, 'height': 500 }, 'picture': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', }, 'content_3': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', 'content_4': '', 'content_5': '', 'content_6': '', 'times': 1000000 + 9 }); _arrayChatMessage.add({ 'id': 100, 'type': 2, 'content_1': ' ', 'content_2': { 'picture_mini': { 'url': 'https://img2.baidu.com/it/u=3202947311,1179654885&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500', 'width': 800, 'height': 500 }, 'picture': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', }, 'content_3': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', 'content_4': '', 'content_5': '', 'content_6': '', 'times': 1000000 + 9 }); _arrayChatMessage.add({ 'id': 100, 'type': 2, 'content_1': ' ', 'content_2': { 'picture_mini': { 'url': 'https://lmg.jj20.com/up/allimg/1114/033021091503/210330091503-6-1200.jpg', 'width': 800, 'height': 500 }, 'picture': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', }, 'content_3': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', 'content_4': '', 'content_5': '', 'content_6': '', 'times': 1000000 + 9 }); _arrayChatMessage.add({ 'id': 100, 'type': 2, 'content_1': ' ', 'content_2': { 'picture_mini': { 'url': 'https://lmg.jj20.com/up/allimg/1114/033021091503/210330091503-6-1200.jpg', 'width': 800, 'height': 500 }, 'picture': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', }, 'content_3': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', 'content_4': '', 'content_5': '', 'content_6': '', 'times': 1000000 + 9 }); _arrayChatMessage.add({ 'id': 100, 'type': 2, 'content_1': ' ', 'content_2': { 'picture_mini': { 'url': 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202107%2F16%2F20210716215819_76234.thumb.1000_0.png&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1679722694&t=6ddea52a86e658f1a73f6e0e3865bad6', 'width': 800, 'height': 500 }, 'picture': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', }, 'content_3': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', 'content_4': '', 'content_5': '', 'content_6': '', 'times': 1000000 + 9 }); _arrayChatMessage.add({ 'id': 100, 'type': 2, 'content_1': ' ', 'content_2': { 'picture_mini': { 'url': 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202107%2F16%2F20210716215819_76234.thumb.1000_0.png&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1679722694&t=6ddea52a86e658f1a73f6e0e3865bad6', 'width': 800, 'height': 500 }, 'picture': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', }, 'content_3': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', 'content_4': '', 'content_5': '', 'content_6': '', 'times': 1000000 + 9 }); _arrayChatMessage.add({ 'id': 100, 'type': 2, 'content_1': ' ', 'content_2': { 'picture_mini': { 'url': 'https://photo.tuchong.com/4274381/f/1139873881.jpg', 'width': 800, 'height': 500 }, 'picture': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', }, 'content_3': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', 'content_4': '', 'content_5': '', 'content_6': '', 'times': 1000000 + 9 }); _arrayChatMessage.add({ 'id': 100, 'type': 2, 'content_1': ' ', 'content_2': { 'picture_mini': { 'url': 'https://photo.tuchong.com/4274381/f/11398738812.jpg', 'width': 800, 'height': 500 }, 'picture': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', }, 'content_3': 'https://user-info-1302720239.cos.ap-nanjing.myqcloud.com/userIcon/user_icon_000100.jpg', 'content_4': '', 'content_5': '', 'content_6': '', 'times': 1000000 + 9 }); //print('--datum:${widget.userInfoOther}'); } @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( backgroundColor: AppColor.colorEDEDED, shadowColor: AppColor.colordddddd, elevation: 1.cale, leading: AppWidget.iconBack(() { AppNavigator().navigateBack(); }), centerTitle: true, title: Text( widget.userInfoOther['name'], style: AppTextStyle.textStyle_34_000000, ), actions: [ Padding( padding: EdgeInsets.only(right: 24.cale), child: AppWidget.inkWellEffectNone( onTap: () {}, child: Icon( AppIcon.dot3, size: 46.cale, color: Colors.black, ), ), ) ], ), body: ChangeNotifierProvider<ProviderChatContent>( create: (BuildContext context) => ProviderChatContent(), child: Builder( builder: (BuildContext context) { return Column( children: [ Expanded( child: AppWidget.inkWellEffectNone( onTap: () { FocusScope.of(context).requestFocus( FocusNode(), ); context .read<ProviderChatContent>() .updateContentShow(false); }, child: ListView.builder( padding: EdgeInsets.symmetric(vertical: 30.cale), physics: const BouncingScrollPhysics( parent: AlwaysScrollableScrollPhysics(), ), shrinkWrap: false, reverse: _arrayChatMessage.length > 7, itemCount: _arrayChatMessage.length, // itemExtent: 188.cale, itemBuilder: (BuildContext context, int index) { if (index % 2 != 0) { return ChatElementSelf( userInfo: widget.userInfoOther, chatMessage: _arrayChatMessage[index], ); } else { return ChatElementOther( userInfo: widget.userInfoOther, chatMessage: _arrayChatMessage[index]); } }, ), ), ), Consumer(builder: (BuildContext context, ProviderChatContent providerChatContent, child) { return ChatBottom( providerChatContent: providerChatContent, ); }), ], ); }, ), ), ); } @override void dispose() { super.dispose(); } }
provider_chat_content.dart
import 'package:flutter/cupertino.dart'; import 'package:imflutter/wrap/extension/extension.dart'; ///用于 软键盘区/发送附件 域显示控制 class ProviderChatContent extends ChangeNotifier { bool _contentShow = false; double _keyboardHeight = 200; /// 是否显示 附件区域 bool get contentShow => _contentShow; /// 键盘高度 double get keyboardHeight => _keyboardHeight - 20.cale; ///更新区域 展示 void updateContentShow(bool isShow) { _contentShow = isShow; notifyListeners(); } void updateKeyboardHeight(double height) { _keyboardHeight = height; notifyListeners(); } }
到此这篇关于flutter 微信聊天输入框的文章就介绍到这了,更多相关flutter 微信聊天输入框内容请搜索好代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持好代码网!