Flutter高仿微信系列共59篇,从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。
效果图:
实现代码:
/** * Author : wangning * Email : maoning20080809@163.com * Date : 2022/9/23 22:51 * Description : 消息页面 */ class MainChat extends StatefulWidget { const MainChat({super.key}); @override _MainChatState createState() => _MainChatState(); } //WidgetsBindingObserver返回按键监听无效, 点击home建才有用 //class _MainChatState extends State<MainChat> with AutomaticKeepAliveClientMixin, WidgetsBindingObserver{ class _MainChatState extends State<MainChat> with AutomaticKeepAliveClientMixin{ //必须要实现wantKeepAlive方法,否则点击底部按钮, 会出现重新初始化initState方法 @override bool get wantKeepAlive => true; ScrollController _scrollController = ScrollController(); //listview 的控制器 List<ChatTempBean> _chatList = []; bool isLoading = false; var json; //是否正在加载数据 var baseEvent; @override void initState() { super.initState(); _initEvent(); _getData(); } @override void dispose() { super.dispose(); eventBus.off(baseEvent); } void _initEvent(){ baseEvent = eventBus.on<BaseEvent>((baseBean) { if(baseEvent != null && (baseBean.type == BaseEvent.TYPE_NEW_MESSAGE || baseBean.type == BaseEvent.TYPE_UPDATE_CHAT_STATUS || baseBean.type == BaseEvent.TYPE_SEND_MESSAGE || baseBean.type == BaseEvent.TYPE_REFRESH_GROUP)){ //接收新消息 Map<String, Object> result = baseBean.result; String fromAccount = CommonUtils.getString(result['from_account']); _getData(); } }); } //加载数据 _getData() async { String account = SpUtils.getString(CommonUtils.LOGIN_ACCOUNT); List<ChatTempBean>? chatList = await ChatRepository.getInstance().getLastChatByName(account); setState(() { _chatList = chatList??[]; }); } //删除单聊信息 _deleteChatByFromToAccount(ChatTempBean chatTempBean) async{ String fromAccount = chatTempBean.account; String toAccount = SpUtils.getString(CommonUtils.LOGIN_ACCOUNT); await ChatRepository.getInstance().deleteChatByFromToAccount(fromAccount, toAccount); await ChatRepository.getInstance().deleteChatByFromToAccount(toAccount, fromAccount); CommonToast.show(context, "删除成功!"); eventBus.emit(BaseEvent(BaseEvent.TYPE_UPDATE_CHAT_STATUS, result: HashMap<String, Object>())); //删除完成重新加载 _getData(); } //删除群聊信息 _deleteGroupChatByGroupId(String groupId) async{ GroupChatRepository.getInstance().deleteAllGroupChatByGroupId(groupId); CommonToast.show(context, "删除成功!"); eventBus.emit(BaseEvent(BaseEvent.TYPE_UPDATE_CHAT_STATUS, result: HashMap<String, Object>())); _getData(); } @override Widget build(BuildContext context) { return Scaffold( body: ListView.builder( itemCount: _chatList.length, controller: _scrollController, itemBuilder: (context, index) { return InkWell( onLongPress: (){ _showDeleteDialog(_chatList[index]); }, onTap: (){ Map<String, Object> result = HashMap<String, Object>(); result["toChatId"] = _chatList[index].account; if(_chatList[index].chatType == ChatTempBean.TYPE_GROUP_CHAT){ //群聊 Navigator.pushNamed(context, Routes.group_chat_main, arguments: { "groupId":_chatList[index].account //参数map }); } else { //单聊 Navigator.push(context,MaterialPageRoute(builder: (context)=>HomeChatPage(toChatId: _chatList[index].account))) .then((flag) { //返回刷新页面 _getData(); setState(() {}); // you may need to call this if you want to update UI }); } }, child: Container( decoration: BoxDecoration(border: Border(bottom:BorderSide(color: Color(0xffd9d9d9), width: 0.3))), padding: EdgeInsets.only(left: 14, top: 12, bottom: 10), child: Row( children: [ _getAvatarDot(_chatList[index].account, _chatList[index].avatar, _chatList[index].newMessageCount), SizedBox(width: 12,), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(_chatList[index].name, maxLines: 1,style: TextStyle(fontSize: 18, color: Colors.black, fontWeight: FontWeight.bold),), Container( width: 200, child: Text(_chatList[index].content, maxLines: 1,overflow : TextOverflow.ellipsis, style: TextStyle(fontSize: 14, color: Colors.grey),), ), ], ), Expanded(child: SizedBox()), Text("${WnDateUtils.getChatLastTime(_chatList[index].addTime)}"), SizedBox(width: 20,), ], ), ), ); } ) ); } //删除对话框(单聊、群聊) Future<void> _showDeleteDialog(ChatTempBean chatTempBean) async { String title = "确定要删除该消息吗?"; if(chatTempBean.chatType == ChatTempBean.TYPE_GROUP_CHAT){ title = "确定要清空该群的消息吗?"; } return showDialog<Null>( context: context, barrierDismissible: false, builder: (BuildContext context) { return AlertDialog( title: Text(title, style: new TextStyle(fontSize: 17.0)), actions: <Widget>[ MaterialButton( child: Text('取消'), onPressed: (){ LogUtils.d("确定取消"); Navigator.of(context).pop(); }, ), MaterialButton( child: Text('确定'), onPressed: (){ LogUtils.d("确定删除"); Navigator.pop(context); if(chatTempBean.chatType == ChatTempBean.TYPE_GROUP_CHAT){ //删除群聊 _deleteGroupChatByGroupId(chatTempBean.account); } else { //删除单聊 _deleteChatByFromToAccount(chatTempBean); } }, ) ], ); } ); } //获取头像小红点 Widget _getAvatarDot(String account, String avatar, int newMessageCount) { LogUtils.d("获取头像小红点 ${newMessageCount}"); if(newMessageCount <= 0) { return CommonAvatarView.showBaseImage(avatar); } else { return Badge( animationType: BadgeAnimationType.scale, badgeContent: Text("${newMessageCount}", style: TextStyle(color: Colors.white),), child: CommonAvatarView.showBaseImage(avatar), ); } } }