高仿微信聊天输入框,效果图如下(目前都是静态展示,服务还没开始开发):
大家如果观察仔细的话 应该会发现,他输入框下面的高度 刚好就是 软键盘的高度;所以在这里就需要监听软键盘的高度。还要配置
resizeToAvoidBottomInset: false,return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar((因为CSDN 严格限制 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 聊天键盘显示 事件的传递 /键盘高度的处理
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();
}
}
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;
}
}
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;
}
}
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: "输入错误",
),
);
}
}
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();
}
}
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();
}
}
前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
@作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors 1、什么是behaviors 2、behaviors的工作方式 3、创建behavior 4、导入并使用behavior 5、behavior中所有可用的节点 6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors 1、什么是behaviorsbehaviors是小程序中,用于实现
这是针对我无法破坏的现有公共(public)API,但我确实希望对其进行扩展。目前,该方法采用字符串或符号或任何其他在作为第一个参数传递给send时有意义的内容我想添加发送字符串、符号等列表的功能。我可以只使用is_a吗?数组,但还有其他发送列表的方法,这不是很像ruby。我将调用列表中的map,所以第一个倾向是使用respond_to?:map。但是字符串也会响应:map,所以这行不通。 最佳答案 如何将它们全部视为数组?String的行为与仅包含String的Array相同:deffoo(obj,arg)[*arg].eac
我的ruby脚本从命令行参数获取某些输入。它检查是否缺少任何命令行参数,然后提示用户输入。但是我无法使用gets从用户那里获得输入。示例代码:test.rbname=""ARGV.eachdo|a|ifa.include?('-n')name=aputs"Argument:#{a}"endendifname==""puts"entername:"name=getsputsnameend运行脚本:rubytest.rbraghav-k错误结果:test.rb:6:in`gets':Nosuchfileordirectory-raghav-k(Errno::ENOENT)fromtes
我正在为我的用户实现一些rubyonrails代码推特内容。我正在创建正确的oauth链接...类似http://twitter.com/oauth/authorize?oauth_token=y2RkuftYAEkbEuIF7zKMuzWN30O2XxM8U9j0egtzKv但在我的测试帐户授予对twitter的访问权限后,它会弹出一个页面,上面写着“您已成功授予对.我不知道用户应该在哪里输入此PIN以及他们为什么必须这样做。我认为这不是必要的步骤。Twitter应该将用户重定向到我在应用程序设置中提供的回调URL。有谁知道为什么会这样?更新我找到了thisarticle声明我需
我相信我对这个问题有一个很好的答案,但我想确保ruby-philes没有更好的方法来做到这一点。基本上,给定一个输入字符串,我想在适当的情况下将该字符串转换为整数,或在适当的情况下将其转换为float。否则,只返回字符串。我会在下面发布我的答案,但我想知道是否有更好的方法。例如:to_f_or_i_or_s("0523.49")#=>523.49to_f_or_i_or_s("0000029")#=>29to_f_or_i_or_s("kittens")#=>"kittens" 最佳答案 我会尽可能避免在Ruby中使用正则表达式
参考文章搭建文章gitte源码在线体验可以注册两个号来测试演示图:一.整体介绍 介绍SignalR一种通讯模型Hub(中心模型,或者叫集线器模型),调用这个模型写好的方法,去发送消息。 内容有: ①:Hub模型的方法介绍 ②:服务器端代码介绍 ③:前端vue3安装并调用后端方法 ④:聊天室样例整体流程:1、进入网站->调用连接SignalR的方法2、与好友发送消息->调用SignalR的自定义方法 前端通过,signalR内置方法.invoke() 去请求接口3、监听接受方法(渲染消息)通过new signalR.HubConnectionBuilder().on
提供3种Ubuntu系统安装微信的方法,在Ubuntu20.04上验证都ok。1.WineHQ7.0安装微信:ubuntu20.04安装最新版微信--可以支持微信最新版,但是适配的不是特别好;比如WeChartOCR.exe报错。2.原生微信安装:linux系统下的微信安装(ubuntu20.04)--微信适配的最好,反应最快,但是微信版本只到2.1.1,版本太老,很多功能都没有。3.深度deepin-wine6安装微信:ubuntu20.04+系统deepin-wine6安装新版微信--综合比较好,当前个人使用此种方法1个月,微信版本3.4;没什么大问题,尚可。一、WineHQ7.0安装微信
对传统的餐饮商家来说,小程序很好地解决了餐厅线下线上连接的问题,在引流获客、节约人力、营销宣传、塑造会员体系、改善消费体验等方面都有很大帮助。小程序点餐可以帮助餐饮企业节省一大把人力开支。一个包含扫码点单、菜品管理、优惠券推送、外卖配送的小程序,商家花几万元就能完成开发测试并投入。商家为什么要开通“扫码点餐”1.解决服务员不够用的问题。2.不怕顾客跑单漏单。3.在微信就能管理菜品、查看营业额。4.订单小票显示顾客桌号和已点菜品。5.可在“附近的小程序”找到您的门店。如今餐饮业常用的三种经营模式:1堂食点单模式客人通过小程序堂食点单。商家可以在微信扫码点餐小程序管理后台根据自己店内情况来设置不同