import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:jydj/assets_tool/images.dart'; import 'package:jydj/hj_utils/api_service/common_service.dart'; import 'package:jydj/hj_utils/screen.dart'; import 'package:visibility_detector/visibility_detector.dart'; import '../../hj_model/splash/ads_model.dart'; import '../../routers/jump_router.dart'; import '../../track_event_manager/track_manager.dart'; import '../widget/net_image_widget.dart'; enum AdShowType { img, //纯图片 hor, //水平:左图标题 + 右下载按钮 vImgText, //图文:上图下文 splash, //启动全屏图 } /// 广告项:按 [AdShowType] 出不同样式(不传是上图下标题的九宫格项);进入可视区上报曝光,点击按链接跳转并上报 class AdsItem extends StatefulWidget { final AdsInfoModel adInfo; final AdShowType? showType; final double? aspectRatio; final double borderRadius; //纯图样式的圆角 final int clickType; //点击上报类型 0:应用 1:广告 final AdExposureModel? exposureModel; final Widget? child; //自定义子视图(IM 广告用) final VoidCallback? onTap; //点击附加回调(IM 广告已读上报用) const AdsItem({ super.key, required this.adInfo, this.showType, this.aspectRatio, this.borderRadius = 12, this.clickType = 1, this.exposureModel, this.child, this.onTap, }); @override State createState() => _AdsItemState(); } class _AdsItemState extends State with AdExposureMixin { AdsInfoModel get adInfo => widget.adInfo; AdExposureModel? get exposureModel => widget.exposureModel; //⚠️ 曝光去重 key 必须稳定 Key get _visibilityKey => ValueKey( 'ad_${adInfo.id ?? adInfo.href ?? ''}_${exposureModel?.pageType?.name ?? ''}_${exposureModel?.tabIndex}', ); @override Widget build(BuildContext context) { return VisibilityDetector( key: _visibilityKey, onVisibilityChanged: (info) { if (info.visibleFraction > 0.1) _expose(); }, child: InkWell( enableFeedback: false, onTap: _onTap, child: widget.child ?? switch (widget.showType) { AdShowType.img => _image(), AdShowType.hor => _hor(), AdShowType.vImgText => _imageText(), AdShowType.splash => _splash(), null => _normal(), }, ), ); } //进入可视区上报曝光 void _expose() { WidgetsBinding.instance.addPostFrameCallback((_) { if (!mounted || exposureModel?.pageType == null) return; adExposure(adInfo: adInfo, exposureModel: exposureModel); }); } void _onTap() { pushToPageByLink( adInfo.href, id: adInfo.id, arguments: { 'pageType': exposureModel?.pageType ?? TrackEventPageType.acgHome, 'adInfo': adInfo, 'payload': {'ad_type': exposureModel?.adType?.value ?? ''}, }, ); CommonService.adsClick(widget.clickType); widget.onTap?.call(); } //启动全屏图:封面铺满 + 兜底背景图 Widget _splash() { return NetworkImageLoader( imageUrl: adInfo.cover ?? '', width: Get.width, height: Get.height, fit: BoxFit.cover, placeHolderWidget: Image.asset('ic_splash_bg.webp'.launchPath, fit: BoxFit.cover, width: Get.width, height: Get.height), ); } //默认样式:上图下标题(九宫格项) Widget _normal() { return Column( children: [ AspectRatio( aspectRatio: widget.aspectRatio ?? 1, child: NetworkImageLoader(imageUrl: adInfo.cover ?? '', borderRadius: 12), ), const Spacer(), Text( adInfo.title?.trim() ?? '', maxLines: 1, style: const TextStyle(color: Color(0xffFAFAFA), fontSize: 11), ), const Spacer(), ], ); } //图文样式:上图下文 Widget _imageText() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ AspectRatio( aspectRatio: 72 / 20, child: NetworkImageLoader( borderRadius: 4, imageUrl: adInfo.cover ?? '', width: double.infinity, height: double.infinity, fit: BoxFit.fill, ), ), 10.sizeBoxH, Text( adInfo.title ?? '', style: const TextStyle(color: Color(0xffdddfdf), fontWeight: FontWeight.w300, fontSize: 12), ), ], ); } //纯图样式:可选宽高比 Widget _image() { final image = NetworkImageLoader( imageUrl: adInfo.cover ?? '', borderRadius: widget.borderRadius, fit: BoxFit.fill, ); final ratio = widget.aspectRatio; return ratio == null ? image : AspectRatio(aspectRatio: ratio, child: image); } //水平样式:左图 + 标题,右「立即下载」按钮 Widget _hor() { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ //图片自己切 10 的圆角 NetworkImageLoader(imageUrl: adInfo.cover ?? '', borderRadius: 10, width: 50, height: 50), 10.sizeBoxW, Text( adInfo.title ?? '', style: const TextStyle(color: Colors.white, fontWeight: FontWeight.w300, fontSize: 12), ), ], ), Container( width: 72, height: 28, decoration: BoxDecoration(color: const Color(0xff3476FF), borderRadius: BorderRadius.circular(14)), child: const Center(child: Text('立即下载', style: TextStyle(color: Colors.white, fontSize: 12))), ), ], ); } }