import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hgdj/assets_tool/images.dart'; import '../../hj_model/splash/ads_model.dart'; import '../../hj_utils/screen.dart'; import '../../tools_base/banner/ads_banner_widget.dart'; import '../../tools_base/banner/ads_item.dart'; class AppCenterDialog extends StatefulWidget { final List? appList; final List? adsList; final VoidCallback? callback; const AppCenterDialog({super.key, this.appList, this.callback, this.adsList}); @override State createState() => _AppCenterDialogState(); } class _AppCenterDialogState extends State { bool _showClose = false; List get _appList => widget.appList ?? []; /// 网格高度上限 = 4 行 + 底部留白,超出滚动。数字跟下面 gridDelegate 对应,改一处要同步。 /// 别用「首帧 shrinkWrap 量高度、次帧再改成固定高」那套——两帧布局不同,弹窗又居中,打开瞬间会跳 double get _maxGridHeight { final itemWidth = (Get.width - 32 * 2 - 12 * 3) / 4; return itemWidth * 93 / 68 * 4 + 16 * 3 + 25; } @override void initState() { super.initState(); // 1 秒后再显示关闭按钮,防误触 Future.delayed(const Duration(milliseconds: 1000), () { if (mounted) setState(() => _showClose = true); }); } @override Widget build(BuildContext context) { return Material( color: Colors.black.withValues(alpha: 0.6), child: Center( child: Container( padding: const EdgeInsets.symmetric(horizontal: 32), alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ if (widget.adsList?.isNotEmpty == true) Container( margin: const EdgeInsets.only(bottom: 24), child: AdsBannerWidget( widget.adsList, width: 329, height: 88, autoPlayMs: 5000, ), ), //Flexible 兜住矮屏:内容再多也不会顶破屏幕 Flexible( child: ConstrainedBox( constraints: BoxConstraints(maxHeight: _maxGridHeight), child: GridView.builder( padding: const EdgeInsets.only(bottom: 25), shrinkWrap: true, //不足 4 行时按内容收,不留空 physics: const ClampingScrollPhysics(), itemCount: _appList.length, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, crossAxisSpacing: 12, mainAxisSpacing: 16, childAspectRatio: 68 / 93, ), itemBuilder: (context, index) { return AdsItem( adInfo: _appList[index], ); }, ), ), ), 32.sizeBoxH, //一直挂在树上只切显隐:等 _showClose 才 build 的话,asset 解码前图高是 0, //会先塌一下再弹回来,居中布局跟着抖 Opacity( opacity: _showClose ? 1 : 0, child: IgnorePointer( ignoring: !_showClose, child: GestureDetector( onTap: () => Get.back(), child: Image.asset("close_button.png".commonImgPath, width: 32, height: 32), ), ), ), ], ), ), ), ); } }