/// 可拖拽广告红包组件 library; import 'package:flutter/material.dart'; class Ads extends StatefulWidget { const Ads({super.key}); @override State createState() => _AdsState(); } class _AdsState extends State with WidgetsBindingObserver { double winWidth = 0.0; double winHeight = 0.0; double dx = 10.0; double dy = 120.0; double ballWidth = 50.0; double ballHeight = 50.0; bool isAnimate = false; // 是否显示 bool isVisible = true; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addPostFrameCallback((_) { updateResize(); }); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } // 监听窗口尺寸变化 @override void didChangeMetrics() { super.didChangeMetrics(); WidgetsBinding.instance.addPostFrameCallback((_) { updateResize(); }); } // 更新设备尺寸 void updateResize() { setState(() { winWidth = MediaQuery.of(context).size.width; winHeight = MediaQuery.of(context).size.height; }); } // 拖拽更新 void onPanUpdate(Offset position) { isAnimate = false; dx = position.dx - ballWidth / 2; dy = position.dy - ballHeight / 2; setState(() {}); } // 拖拽结束 void onPanEnd(Offset position) { isAnimate = true; if (dx + ballWidth / 2 < winWidth / 2) { dx = 10.0; } else { dx = winWidth - ballWidth - 10.0; } if (dy + ballHeight > winHeight / 2) { dy = winHeight / 2 - ballHeight; } else if (dy < 120) { dy = 120.0; } setState(() {}); } @override Widget build(BuildContext context) { return Visibility( visible: isVisible, child: AnimatedPositioned( duration: Duration(milliseconds: isAnimate ? 200 : 0), left: dx, top: dy, child: GestureDetector( behavior: HitTestBehavior.opaque, onPanUpdate: (DragUpdateDetails details) { onPanUpdate(details.globalPosition); }, onPanEnd: (details) { onPanEnd(details.globalPosition); }, onTap: () { debugPrint('click ads'); }, child: Stack( children: [ SizedBox( height: ballHeight, width: ballWidth, child: UnconstrainedBox( child: Container( height: 40.0, width: 40.0, decoration: BoxDecoration( color: Colors.black.withAlpha(50), borderRadius: BorderRadius.circular(100.0), ), child: UnconstrainedBox( child: Image.asset( 'assets/images/hbico.png', width: 25.0, fit: BoxFit.contain, ), ), ), )), Positioned( right: 0, top: 0, child: GestureDetector( child: Icon( Icons.close, color: Colors.white, size: 10.0, ), onTap: () { setState(() { isVisible = false; }); }, ), ), ], ), ), ), ); } }