Flutter高仿微信系列共59篇,从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。
效果图:
详情请参考 Flutter高仿微信-第29篇-单聊 , 这里只是提取红包功能的部分代码。
实现代码:
//我的红包 Widget meRedpacketWidget(){ return GestureDetector( onTap: (){ //点击红包 Navigator.push(context, MaterialPageRoute(builder: (context) => ReceiveRedpacketSuccess(fromUser: widget.meUserBean?.account??"", toUser: widget.otherUserBean?.account??"", balance: widget.chatBean?.content??"", addTime: widget.chatBean.addTime??"",))); }, child: Container( child: Stack( children: [ meRedpacketBackground(), Positioned( left: 20, top: 20, child:CommonUtils.getBaseIconPng("wc_redpacket_icon", width: 40, height: 40), ), Positioned( left: 70, top: 30, child: Text("恭喜发财,大吉大利", style: TextStyle(fontSize: 12, color: Colors.white, fontWeight: FontWeight.bold),), ), Positioned( left: 70, top: 50, child: Container( margin: EdgeInsets.only(top:10), width: 120, height: 1, color: Colors.white, ), ), Positioned( left: 20, bottom: 14, child:Text("私人红包", style: TextStyle(fontSize: 12, color: Colors.white38),), ), ], ), ), ); }
//朋友发来的红包 Widget toRedpacketWidget(){ return GestureDetector( onTap: (){ if(widget.chatBean.isClick == 1){ Navigator.push(context, MaterialPageRoute(builder: (context) => ReceiveRedpacketSuccess(fromUser: widget.meUserBean?.account??"", toUser: widget.otherUserBean?.account??"", balance: widget.chatBean?.content??"", addTime: widget.chatBean.addTime??"",))); } else { showRedPacket(context, _onOpenRedpacket, widget.otherUserBean?.account, widget.chatBean?.content??"", widget.index); } }, child: Opacity( opacity: widget.chatBean.isClick == 1 ? 0.6 :1, child: Container( child: Stack( children: [ toRedpacketBackground(), Positioned( left: 38, top: 20, child:CommonUtils.getBaseIconPng("wc_redpacket_icon", width: 40, height: 40), ), Positioned( left: 88, top: 30, child: Text("恭喜发财,大吉大利", style: TextStyle(fontSize: 12, color: Colors.white, fontWeight: FontWeight.bold),), ), Positioned( left: 88, top: 50, child: Container( margin: EdgeInsets.only(top:10), width: 120, height: 1, color: Colors.white, ), ), Positioned( left: 38, bottom: 14, child:Text("私人红包", style: TextStyle(fontSize:12, color: Colors.white38),), ), ], ), ), ), ); }
//红包背景 Widget toRedpacketBackground(){ return CustomPaint( painter: RedPacketOther( strokeColor: Color(0xFFf58220), paintingStyle: PaintingStyle.fill, ), child: Container( height: 100, width: 280, ), ); }
/** * Author : wangning * Email : maoning20080809@163.com * Date : 2022/9/24 12:09 * Description : 点击查看红包弹出框 */ void showRedPacket(BuildContext context, Function? onOpen, String? toUser, String balance, int position){ entry = OverlayEntry(builder: (context) => RedPacket(onFinish: _removeRedPacket, onOpen: onOpen, toUser: toUser, balance: balance, position: position,)); Overlay.of(context)?.insert(entry!); } void _removeRedPacket(){ entry?.remove(); entry = null; } class RedPacket extends StatefulWidget { String? toUser; String? balance; int? position; Function? onFinish; Function? onOpen; RedPacket({Key? key,this.onFinish, this.onOpen, this.toUser, this.balance, this.position}) : super(key: key); @override _RedPacketState createState() => _RedPacketState(); } class _RedPacketState extends State<RedPacket> with TickerProviderStateMixin{ UserBean? _toUserBean; late RedPacketController controller = RedPacketController(tickerProvider: this); @override void initState() { super.initState(); controller.onOpen = widget.onOpen; controller.onFinish = widget.onFinish; _initUser(); } _initUser() async { _toUserBean = await UserRepository.getInstance().findUserByAccount(widget.toUser??""); setState(() { }); } @override void dispose() { controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Material( color: Color(0x88000000), child: GestureDetector( child: ScaleTransition( scale: Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation(parent: controller.scaleController, curve: Curves.fastOutSlowIn)), child: buildRedPacket(), ), //onPanDown: (d) => controller.handleClick(d.globalPosition), onPanDown: (d){ _handleClick(d); }, ), ); } void _handleClick(d) async { bool isNetwork = await CommonNetwork.isNetwork(); if(!isNetwork) { CommonUtils.showNetworkError(context); return; } controller.handleClick(d.globalPosition, widget.position, widget.balance); } Widget buildRedPacket() { return GestureDetector( onTapUp: controller.clickGold, child: CustomPaint( size: Size(1.sw, 1.sh), painter: RedPacketPainter(controller: controller), child: buildChild(), ), ); } Widget buildChild() { return AnimatedBuilder( animation: controller.translateController, builder: (context, child) => Container( padding: EdgeInsets.only(top: 0.3.sh * (1 - controller.translateCtrl.value)), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ClipRRect( borderRadius: BorderRadius.circular(3.w), child: CommonAvatarView.showBaseImage(_toUserBean?.avatar??""), ), SizedBox(width: 5.w,), Text("${_toUserBean?.nickName}", style: TextStyle(fontSize: 16.sp, color: Color( 0xFFF8E7CB), fontWeight: FontWeight.w500),) ], ), SizedBox(height: 15.w,), Text("恭喜发财,大吉大利", style: TextStyle(fontSize: 18.sp, color: Color( 0xFFF8E7CB)),) ], ), ), ); } }
/** * Author : wangning * Email : maoning20080809@163.com * Date : 2022/11/1 19:51 * Description : 领取红包成功页面 */ class ReceiveRedpacketSuccess extends StatefulWidget{ String balance; String toUser; String fromUser; String addTime; ReceiveRedpacketSuccess({required this.fromUser, required this.toUser, required this.balance, required this.addTime}); @override State<StatefulWidget> createState() => _ReceiveRedpacketSuccessState(); } class _ReceiveRedpacketSuccessState extends State<ReceiveRedpacketSuccess>{ UserBean? _fromUserBean; UserBean? _toUserBean; @override void initState() { super.initState(); _initUser(); } void _initUser() async { _fromUserBean = await UserRepository.getInstance().findUserByAccount(widget.fromUser); _toUserBean = await UserRepository.getInstance().findUserByAccount(widget.toUser); LogUtils.d("账号:${widget.fromUser} , ${_fromUserBean?.toJson()}"); setState(() { }); } @override Widget build(BuildContext context) { return Scaffold( appBar: WnAppBar.getAppBar(context, Text("红包")), body: Container( child: Column( children: [ nameWidget(), SizedBox(height: 10,), tipWidget(), SizedBox(height: 30,), balanceWidget(), SizedBox(height: 80,), meInfoWidget(), ], ), ), ); } //头像、昵称 Widget nameWidget(){ return Container( margin: EdgeInsets.only(top: 30), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ CommonAvatarView.showBaseImage(_toUserBean?.avatar??""), SizedBox(width: 10,), Text(_toUserBean?.nickName??"", style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),), ], ), ); } Widget tipWidget(){ return Text("恭喜发财,大吉大利", style: TextStyle(fontSize: 20, color: Colors.grey.shade600),); } //金额 Widget balanceWidget(){ return Container( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("${widget.balance}", style: TextStyle(fontSize: 48, color: Color(0xFFFFA500)),), Baseline(baseline: 36.0, //对齐字符底部水平线 baselineType: TextBaseline.alphabetic, child: Text("元", style: TextStyle(fontSize: 18, color: Color(0xFFFFA500)),), ), ], ), ); } //我的个人信息 Widget meInfoWidget(){ String addTime = WnDateUtils.changeHM(widget.addTime??""); return Container( child: Stack( children: [ Row( children: [ Container( margin: EdgeInsets.only(left: 12, top: 12, right: 12), child: CommonAvatarView.showBaseImage(_fromUserBean?.avatar??"", 62, 62), ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 10,), Text(_fromUserBean?.nickName??"", style: TextStyle(fontSize: 20),), Text(addTime, style: TextStyle(fontSize: 20, color: Colors.grey.shade500),), ], ), Expanded(child: Text("")), Container( margin: EdgeInsets.only(right: 12), child: Text("${widget.balance}元", style: TextStyle(fontSize: 20),), ), ], ), Positioned( bottom: 1, right: 1, child: Container( margin: EdgeInsets.only(right: 12), width: 300, height: 1, color: Colors.grey.shade400 , ), ), ], ), ); } }