Flutter高仿微信系列共59篇,从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。
Flutter高仿微信(支持Android和IOS系统)
Flutter高仿微信主要包含5大模块:
效果图:
实现代码:
/** * Author : wangning * Email : maoning20080809@163.com * Date : 2022/9/23 22:51 * Description : 注册 */ class Register extends StatelessWidget { const Register({super.key}); @override Widget build(BuildContext context) { return const RegisterPage(title: '注册页面'); } } class RegisterPage extends StatefulWidget { const RegisterPage({super.key, required this.title}); final String title; @override State<RegisterPage> createState() => _RegisterPageState(); } class _RegisterPageState extends State<RegisterPage> { bool loadingVisible = false; String account = SpUtils.getString(CommonUtils.LOGIN_ACCOUNT); final TextEditingController _usernameController = TextEditingController(text: ""); final TextEditingController _passwordController = TextEditingController(text: ""); final TextEditingController _confirmPasswordController = TextEditingController(text: ""); String _username = ''; String _password = ''; String _confirmPassword = ''; void _init(BuildContext context){ //初始化 FlutterXmpp.init(CommonUtils.BASE_IP, CommonUtils.BASE_XMPP_PORT, domin: "wangning"); //xmpp注册监听回调 FlutterXmpp.addListener( onConnect: (event){ setState(() { }); }, onReceiveMessage: (event){ }, onLogin: (event){ }, onRegister: (event){ LogUtils.d("返回注册信息:${event} , ${event["code"]}"); var code = int.parse(event["code"]); if(code == 200){ //注册成功,账号数据插入本地数据库和同步到服务器 account = _usernameController.text; UserBean userBean = UserBean(account: account, nickName: account, name: account, balance: 0); UserRepository.getInstance().insertUserLocal(userBean); UserRepository.getInstance().insertUserServer(userBean); CommonToast.show(context, "注册成功!", duration: Toast.lengthLong); Navigator.pop(context); } else if(code == 409){ CommonToast.show(context, "用户已存在!"); } else { CommonToast.show(context, "注册失败!"); } setState(() { loadingVisible = false; }); } ); } //显示loading框 void _showLoadingDialog() { setState(() { loadingVisible = true; }); Future.delayed(const Duration(seconds: 30),(){ setState(() { loadingVisible = false; }); }); } void _submitRegister() async { bool isNetwork = await CommonNetwork.isNetwork(); if(!isNetwork) { CommonUtils.showNetworkError(context); return; } String username = _usernameController.text; String password = _passwordController.text; String confirmPassword = _confirmPasswordController.text; LogUtils.d("注册获取值:${username} , "); if(username.isEmpty){ CommonToast.show(context, "请输入账号"); } else if(username.length < 6 || username.length > 18){ CommonToast.show(context, "账号6-18位"); } else if(password.isEmpty){ CommonToast.show(context, "请输入密码"); } else if(password.length < 6 || password.length > 18){ CommonToast.show(context, "密码6-18位"); } else if(password != confirmPassword){ CommonToast.show(context, "2次密码不一致"); } else { _showLoadingDialog(); //注册结果在FlutterXmpp.addListener中回调 FlutterXmpp.register(username, password); } } @override void initState() { super.initState(); //界面build完成后执行回调函数, 执行_init WidgetsBinding.instance.addPostFrameCallback((_) => _init(context)); } @override Widget build(BuildContext context) { return Stack( children: [ Scaffold( appBar: WnAppBar.getAppBar(context, Text(widget.title)), body: Center( child: SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ _getRoundImage('assets/icons/app_icon.png', 60.0), SizedBox( height: 30, ), _getUsernameInput(), Container( height: 1, margin: EdgeInsets.only(left: 10, right: 10), color: Colors.grey.shade400, ), _getPasswordInput(), Container( height: 1, margin: EdgeInsets.only(left: 10, right: 10), color: Colors.grey.shade400, ), _getConfirmPasswordInput(), Container( height: 1, margin: EdgeInsets.only(left: 10, right: 10), color: Colors.grey.shade400, ), SizedBox( height: 60, ), _getRegisterButton(), ], ), ), ), ), Offstage( offstage: !loadingVisible, child: CommonLoadingDialog(msg: "请稍后。。。",), ), ], ); } //头像 Widget _getRoundImage(String imageName, double size) { return Container( width: size, height: size, clipBehavior: Clip.antiAlias, decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(size / 2)), ), child: Image.asset( imageName, fit: BoxFit.fitWidth, ), ); } //账号输入框 Widget _getUsernameInput() { return Container( height: 50, margin: EdgeInsets.all(10.0), child: TextField( maxLength: 18, keyboardType: TextInputType.emailAddress, obscureText: false, controller: _usernameController, inputFormatters: [ FilteringTextInputFormatter(RegExp("^[a-z0-9A-Z]+"), allow: true),//只允许输入数字,字母 ], decoration: InputDecoration( hintText: "请输入账号", counterText: "", icon: const Icon( Icons.account_box, size: 20.0, ), border: InputBorder.none, //使用 GestureDetector 实现手势识别 suffixIcon: GestureDetector( child: Offstage( child: Icon(Icons.clear), offstage: _username == '', ), //点击清除文本框内容 onTap: () { setState(() { _username = ''; _usernameController.clear(); }); }, ), ), //使用 onChanged 完成双向绑定 onChanged: (value) { setState(() { _username = value; }); }, ), ); } //密码输入框 Widget _getPasswordInput() { return Container( height: 50, margin: EdgeInsets.all(10.0), child: TextField( maxLength: 18, keyboardType: TextInputType.text, obscureText: true, controller: _passwordController, inputFormatters: [ FilteringTextInputFormatter(RegExp("^[a-z0-9A-Z]+"), allow: true),//只允许输入数字,字母 ], decoration: InputDecoration( hintText: "请输入密码", counterText: "", icon: const Icon( Icons.lock_open, size: 20.0, ), suffixIcon: GestureDetector( child: Offstage( child: Icon(Icons.clear), offstage: _password == '', ), onTap: () { setState(() { _password = ''; _passwordController.clear(); }); }, ), border: InputBorder.none, ), onChanged: (value) { setState(() { _password = value; }); }, ), ); } //确认密码输入框 Widget _getConfirmPasswordInput() { return Container( height: 50, margin: EdgeInsets.all(10.0), child: TextField( maxLength: 18, keyboardType: TextInputType.text, obscureText: true, controller: _confirmPasswordController, inputFormatters: [ FilteringTextInputFormatter(RegExp("^[a-z0-9A-Z]+"), allow: true),//只允许输入数字,字母 ], decoration: InputDecoration( hintText: "确认密码", counterText: "", icon: const Icon( Icons.lock_open, size: 20.0, ), suffixIcon: GestureDetector( child: Offstage( child: Icon(Icons.clear), offstage: _confirmPassword == '', ), onTap: () { setState(() { _confirmPassword = ''; _confirmPasswordController.clear(); }); }, ), border: InputBorder.none, ), onChanged: (value) { setState(() { _confirmPassword = value; }); }, ), ); } //注册按钮 Widget _getRegisterButton() { return MaterialButton( color: Colors.blue, textColor: Colors.white, padding: const EdgeInsets.only(left: 28, top: 8, right: 28, bottom: 8), child: const Text('注册',style: TextStyle(fontSize: 16),), onPressed: () { _submitRegister(); }, ); } }