🎯 广告类型
版本 GroMore
📰 Draw信息流广告
Draw信息流广告是一种特殊的信息流广告类型,支持视频暂停控制、自定义渲染等高级功能,区别于传统信息流广告。
📋 与传统信息流广告的区别
特性 | 传统信息流广告 | Draw信息流广告 |
---|---|---|
API方法 | loadFeedAd() | loadDrawFeedAd() |
Widget组件 | AdFeedWidget | AdDrawFeedWidget |
返回对象 | TTFeedAd | TTDrawFeedAd |
视频控制 | 基础播放控制 | 支持暂停/播放控制 |
自定义渲染 | 标准模板 | 支持自定义视频播放器 |
交互功能 | 基础点击事件 | 丰富的视频交互事件 |
Widget 组件方式(推荐)
// 在列表中嵌入Draw信息流广告
class DrawFeedPage extends StatefulWidget {
@override
_DrawFeedPageState createState() => _DrawFeedPageState();
}
class _DrawFeedPageState extends State<DrawFeedPage> {
final List<dynamic> _feedItems = [];
final List<int> _drawAdIds = [];
@override
void initState() {
super.initState();
_loadDrawFeedData();
}
void _loadDrawFeedData() async {
// 加载Draw信息流广告
try {
final List<int> adIds = await GromoreAds.loadDrawFeedAd(
'your_draw_feed_ad_id',
width: 375,
height: 300,
count: 3,
);
setState(() {
_drawAdIds.addAll(adIds);
_buildFeedItems();
});
} catch (e) {
print('Draw信息流广告加载失败: $e');
}
}
void _buildFeedItems() {
// 模拟加载内容数据
final List<String> contentItems = [
'内容1', '内容2', '内容3', '内容4', '内容5',
'内容6', '内容7', '内容8', '内容9', '内容10'
];
_feedItems.clear();
// 在适当位置插入Draw广告
int adIndex = 0;
for (int i = 0; i < contentItems.length; i++) {
_feedItems.add({'type': 'content', 'data': contentItems[i]});
// 每4个内容后插入一个Draw广告
if ((i + 1) % 4 == 0 && adIndex < _drawAdIds.length) {
_feedItems.add({
'type': 'draw_ad',
'adId': _drawAdIds[adIndex],
'posId': 'your_draw_feed_ad_id'
});
adIndex++;
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Draw信息流')),
body: ListView.builder(
itemCount: _feedItems.length,
itemBuilder: (context, index) {
final item = _feedItems[index];
if (item['type'] == 'draw_ad') {
// Draw广告项
return Container(
height: 300,
margin: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: AdDrawFeedWidget(
posId: item['posId'],
adId: item['adId'],
width: MediaQuery.of(context).size.width - 32,
height: 300,
onAdLoaded: () {
print('Draw广告加载成功: ${item['adId']}');
},
onAdError: (error) {
print('Draw广告加载失败: $error');
// 广告加载失败时可以移除该项
setState(() {
_feedItems.removeAt(index);
});
},
onAdClicked: () {
print('Draw广告被点击: ${item['adId']}');
},
// Draw广告特有的视频回调
onVideoPlay: () {
print('Draw广告视频开始播放: ${item['adId']}');
},
onVideoPause: () {
print('Draw广告视频暂停: ${item['adId']}');
},
onVideoComplete: () {
print('Draw广告视频播放完成: ${item['adId']}');
},
),
);
} else {
// 内容项
return ListTile(
title: Text(item['data']),
subtitle: Text('这是一条内容描述'),
leading: Icon(Icons.article),
);
}
},
),
);
}
@override
void dispose() {
// 页面销毁时清理Draw广告
if (_drawAdIds.isNotEmpty) {
GromoreAds.clearDrawFeedAd(_drawAdIds);
}
super.dispose();
}
}
可选参数说明
loadDrawFeedAd
与 loadFeedAd
共用同一套扩展参数,可按需开启聚合功能:
参数 | 类型 | 说明 |
---|---|---|
mutedIfCan | bool | 首次展示静音,兼容 Android / iOS |
volume | double | [Android] 自定义音量(0.0~1.0 ),在 mutedIfCan=false 时生效 |
bidNotify | bool | 启用竞价通知,获知实际填充渠道 |
scenarioId | String | 场景 ID,便于统计与归因 |
useSurfaceView | bool | [Android] 视频采用 SurfaceView 呈现,降低过度绘制 |
extra | Map<String, dynamic> | [Android] 聚合扩展参数,通过 MediationAdSlot#setExtraObject 生效 |
同样地,未显式传入的字段将维持 GroMore 默认行为。
方法调用方式
class DrawFeedAdHelper {
static final Map<String, List<int>> _loadedAds = {};
// 加载Draw信息流广告
static Future<List<int>> loadDrawFeedAd(String posId, {
int width = 375,
int height = 300,
int count = 1,
}) async {
try {
final List<int> adIds = await GromoreAds.loadDrawFeedAd(
posId,
width: width,
height: height,
count: count,
);
_loadedAds[posId] = adIds;
print('Draw信息流广告 $posId 加载成功,获得${adIds.length}个广告');
return adIds;
} catch (e) {
print('Draw信息流广告 $posId 加载异常: $e');
return [];
}
}
// 销毁Draw信息流广告
static Future<void> destroyDrawFeedAd(String posId) async {
final List<int>? adIds = _loadedAds[posId];
if (adIds == null || adIds.isEmpty) return;
try {
await GromoreAds.clearDrawFeedAd(adIds);
_loadedAds.remove(posId);
print('Draw信息流广告 $posId 已销毁');
} catch (e) {
print('Draw信息流广告 $posId 销毁异常: $e');
}
}
// 批量销毁所有Draw信息流广告
static Future<void> destroyAllDrawFeedAds() async {
for (String posId in _loadedAds.keys.toList()) {
await destroyDrawFeedAd(posId);
}
}
}
自适应尺寸Draw信息流
class AdaptiveDrawFeedAd extends StatelessWidget {
final String posId;
final int adId;
final double aspectRatio; // 宽高比
const AdaptiveDrawFeedAd({
Key? key,
required this.posId,
required this.adId,
this.aspectRatio = 1.25, // 默认1.25:1
}) : super(key: key);
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
final adWidth = constraints.maxWidth;
final adHeight = adWidth / aspectRatio;
return Container(
width: adWidth,
height: adHeight,
margin: EdgeInsets.symmetric(vertical: 8),
child: AdDrawFeedWidget(
posId: posId,
adId: adId,
width: adWidth,
height: adHeight,
onAdLoaded: () {
print('自适应Draw广告加载成功: $posId');
},
onAdError: (error) {
print('自适应Draw广告加载失败: $error');
},
onVideoPlay: () {
print('自适应Draw广告视频开始播放');
},
onVideoPause: () {
print('自适应Draw广告视频暂停');
},
),
);
},
);
}
}
AdDrawFeedWidget 参数
参数 | 类型 | 必需 | 说明 |
---|---|---|---|
posId | String | ✅ | Draw信息流广告位 ID |
adId | int | ✅ | 广告数据ID(从loadDrawFeedAd返回) |
width | double | ❌ | 宽度,默认 375 |
height | double | ❌ | 高度,默认 300 |
isVisible | bool | ❌ | 是否可见,默认 true |
onAdLoaded | VoidCallback? | ❌ | 广告加载成功回调 |
onAdError | Function(String)? | ❌ | 广告加载失败回调 |
onAdClicked | VoidCallback? | ❌ | 广告点击回调 |
onAdClosed | VoidCallback? | ❌ | 广告关闭回调 |
onVideoPlay | VoidCallback? | ❌ | Draw特有:视频播放回调 |
onVideoPause | VoidCallback? | ❌ | Draw特有:视频暂停回调 |
onVideoComplete | VoidCallback? | ❌ | Draw特有:视频播放完成回调 |
Draw广告特殊功能
1. 视频控制
AdDrawFeedWidget(
posId: 'your_draw_feed_ad_id',
adId: adId,
onVideoPlay: () {
// 视频开始播放时的处理
print('Draw广告视频开始播放');
},
onVideoPause: () {
// 视频暂停时的处理
print('Draw广告视频暂停');
},
onVideoComplete: () {
// 视频播放完成时的处理
print('Draw广告视频播放完成');
},
)
2. 与内容融合的Draw广告容器
// 创建与内容风格一致的Draw广告容器
Widget _buildDrawFeedItem(dynamic item, int index) {
if (item['type'] == 'draw_ad') {
return Container(
margin: EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 5,
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Draw广告标识
Padding(
padding: EdgeInsets.all(8),
child: Row(
children: [
Icon(Icons.play_circle, size: 12, color: Colors.blue),
SizedBox(width: 4),
Text('Draw广告', style: TextStyle(fontSize: 10, color: Colors.grey)),
],
),
),
// Draw广告内容
AdDrawFeedWidget(
posId: item['posId'],
adId: item['adId'],
width: MediaQuery.of(context).size.width - 24,
height: 280,
onAdLoaded: () => print('Draw广告加载完成'),
onVideoPlay: () => print('Draw视频开始播放'),
),
],
),
);
} else {
// 普通内容项
return _buildContentItem(item);
}
}
常见尺寸和比例
类型 | 尺寸 (宽x高) | 宽高比 | 适用场景 |
---|---|---|---|
标准Draw | 375x300 | 1.25:1 | 通用Draw信息流 |
大屏Draw | 375x280 | 1.34:1 | 强视觉冲击 |
横版Draw | 375x210 | 1.78:1 | 横版视频内容 |
方形Draw | 300x300 | 1:1 | 方形视频展示 |
最佳实践
- 广告密度: Draw广告相比普通信息流广告更具视觉冲击力,建议控制在 1:4 到 1:6 之间
- 尺寸选择: Draw广告建议使用较大尺寸以充分展示视频内容
- 加载策略: Draw广告加载时间可能较长,建议提前预加载
- 交互处理: 利用Draw广告的视频回调优化用户交互体验
- 资源管理: 及时清理不需要的Draw广告实例以释放内存
⚠️ 注意事项
- 区分使用: Draw信息流广告与传统信息流广告是两种不同的广告类型,请勿混用
- API区分: 使用
loadDrawFeedAd()
和AdDrawFeedWidget
,而非loadFeedAd()
- 性能优化: Draw广告通常包含视频内容,注意内存和性能管理
- 事件处理: 充分利用Draw广告特有的视频事件回调
- 兼容性: 确保广告位配置支持Draw广告类型