🎬 短剧模块
版本 PanGrowth
🃏 短剧预览卡片
短剧预览卡片以 16:9 视频预览位的形式在任意页面展示短剧首集或推荐片段,支持自动播放、静音控制、循环播放等能力,可与播放页、聚合页联动实现完整短剧体验。插件同时提供 NativeView 组件 与 API 控制 两条集成路径。
🚪 接入方式概览
方式 | 推荐场景 | 实现特点 |
---|---|---|
NativeView 组件(推荐) | Flutter 页面内嵌卡片,信息流/网格展示 | 使用 DramaCardNativeView ,自动管理创建/销毁,可配合 DramaCardController 与 DramaCardListener |
API 调用 | 需要在原生 Activity/ViewController 展示或精确控制生命周期 | 使用 createDramaCard / showDramaCard / destroyDramaCard 主动控制 |
注意:两种方式的配置对象相同,都使用 DramaCardConfig
。
✅ 方式一:DramaCardNativeView
(推荐)
DramaCardNativeView
通过 PlatformView 内嵌原生短剧卡片,Flutter 层像普通 Widget 一样使用。
基础示例
import 'package:flutter/material.dart';
import 'package:pangrowth_content/pangrowth_content.dart';
class DramaCardWidget extends StatelessWidget {
final int dramaId;
const DramaCardWidget({
super.key,
required this.dramaId,
});
@override
Widget build(BuildContext context) {
return SizedBox(
width: 220,
height: 220 * 9 / 16, // 保持 16:9 比例
child: DramaCardNativeView(
config: DramaCardConfig(
dramaId: dramaId,
width: 220,
isAutoPlay: true,
isMuteDefault: true,
isLooping: false,
),
),
);
}
}
结合 DramaCardListener
使用 DramaCardListener
监听卡片生命周期事件:
DramaCardNativeView(
config: DramaCardConfig(
dramaId: 12345,
width: 220,
isAutoPlay: true,
isMuteDefault: true,
),
listener: DramaCardListener(
onCardReady: (cardId) {
debugPrint('卡片就绪: $cardId');
},
onDataLoaded: (drama) {
debugPrint('短剧数据加载完成: ${drama?.title}');
},
onCardClicked: (cardId) {
// 用户点击卡片,可跳转到播放页
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DramaPlayerPage(dramaId: dramaId),
),
);
},
onCardError: (error) {
debugPrint('卡片加载失败: $error');
},
),
)
结合 DramaCardController
当需要控制卡片播放/暂停时,使用 DramaCardController
:
class CardControlDemo extends StatefulWidget {
const CardControlDemo({super.key});
@override
State<CardControlDemo> createState() => _CardControlDemoState();
}
class _CardControlDemoState extends State<CardControlDemo> {
final _controller = DramaCardController();
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
width: 220,
height: 220 * 9 / 16,
child: DramaCardNativeView(
config: DramaCardConfig(
dramaId: 12345,
width: 220,
isAutoPlay: false, // 不自动播放,由控制器控制
),
controller: _controller,
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => _controller.play(),
child: const Text('播放'),
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: () => _controller.pause(),
child: const Text('暂停'),
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: () => _controller.setMute(true),
child: const Text('静音'),
),
],
),
],
);
}
}
控制器方法
方法 | 说明 |
---|---|
play() | 播放卡片 |
pause() | 暂停卡片 |
stop() | 停止卡片 |
setMute(bool mute) | 设置静音状态 |
refresh() | 刷新卡片数据 |
reportShow(int duration) | 上报曝光埋点(单位毫秒) |
isPlaying() | 查询播放状态 |
getDramaInfo() | 获取短剧信息 |
getGid() | 获取短剧 GID |
getTitle() | 获取短剧标题 |
配置参数:DramaCardConfig
参数 | 类型 | 平台 | 说明 |
---|---|---|---|
必填参数 | |||
dramaId | int | Android / iOS | 短剧 ID |
通用可选参数 | |||
width | int? | Android / iOS | 卡片宽度(dp),高度自动按 16:9 计算 |
isMuteDefault | bool? | Android / iOS | 是否默认静音(建议信息流场景设为 true) |
isLooping | bool? | Android / iOS | 是否循环播放 |
isAutoPlay | bool? | Android / iOS | 是否自动播放 |
iOS 专用参数 | |||
hideActionUI | bool? | @ios | 隐藏操作 UI,可自行叠加自定义按钮 |
hidePlayButton | bool? | @ios | 隐藏播放按钮 |
hideMuteButton | bool? | @ios | 隐藏静音按钮 |
Android 专用参数 | |||
hideSoundButton | bool? | @android | 隐藏声音按钮 |
hideReplayButton | bool? | @android | 隐藏重播按钮 |
生命周期管理
DramaCardNativeView
自动管理卡片生命周期:
- 创建: Widget
initState
时自动创建原生视图 - 显示: Widget
build
时自动显示 - 销毁: Widget
dispose
时自动销毁原生视图
无需手动调用任何销毁方法,Widget 销毁时会自动释放资源。
信息流嵌入示例
class DramaCardList extends StatelessWidget {
final List<int> dramaIds = [12345, 12346, 12347];
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: dramaIds.length,
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: DramaCardNativeView(
config: DramaCardConfig(
dramaId: dramaIds[index],
width: MediaQuery.of(context).size.width.toInt() - 32,
isAutoPlay: true,
isMuteDefault: true, // 信息流默认静音
isLooping: true, // 循环播放吸引注意
hidePlayButton: true, // iOS: 隐藏播放按钮
hideSoundButton: true,// Android: 隐藏声音按钮
),
listener: DramaCardListener(
onCardClicked: (cardId) {
// 点击跳转播放页
_openDramaPlayer(context, dramaIds[index]);
},
),
),
);
},
);
}
}
🧭 方式二:API 控制
适合需要精确控制卡片生命周期的场景,如原生 Activity/ViewController 中展示。
完整生命周期演示
import 'package:flutter/material.dart';
import 'package:pangrowth_content/pangrowth_content.dart';
class DramaCardAPIDemo extends StatefulWidget {
const DramaCardAPIDemo({super.key});
@override
State<DramaCardAPIDemo> createState() => _DramaCardAPIDemoState();
}
class _DramaCardAPIDemoState extends State<DramaCardAPIDemo> {
String? _cardId;
Future<void> _createAndShow() async {
// 1. 创建卡片
final config = DramaCardConfig(
dramaId: 12345,
width: 350,
isAutoPlay: true,
isMuteDefault: false,
);
final result = await PangrowthContent.createDramaCard(config);
if (result['success'] == true) {
_cardId = result['cardId'] as String;
debugPrint('创建成功: $_cardId');
// 2. 显示卡片(全屏弹窗)
await PangrowthContent.showDramaCard(_cardId!);
debugPrint('显示成功');
}
}
Future<void> _destroy() async {
if (_cardId != null) {
await PangrowthContent.destroyDramaCard(_cardId!);
debugPrint('销毁成功');
setState(() {
_cardId = null;
});
}
}
@override
void dispose() {
// 清理资源
if (_cardId != null) {
PangrowthContent.destroyDramaCard(_cardId!);
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('API方式演示')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _cardId == null ? _createAndShow : null,
child: const Text('创建并显示'),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _cardId != null ? _destroy : null,
child: const Text('销毁'),
),
],
),
),
);
}
}
控制接口
方法 | 说明 |
---|---|
createDramaCard(config) | 创建卡片,返回 cardId |
showDramaCard(cardId) | 在原生页面打开卡片容器(Android 启动 Activity,iOS 弹出 ViewController) |
playDramaCard(cardId) | 播放卡片 |
pauseDramaCard(cardId) | 暂停卡片 |
stopDramaCard(cardId) | 停止卡片 |
setDramaCardMute(cardId, mute) | 切换静音状态 |
reportDramaCardShow(cardId, duration) | 上报曝光埋点(单位毫秒) |
refreshDramaCard(cardId) | 重新拉取卡片数据 |
destroyDramaCard(cardId) | 释放卡片并关闭容器 |
isDramaCardPlaying(cardId) | 查询播放状态 |
getDramaCardInfo(cardId) | 获取短剧信息 |
getDramaCardGid(cardId) | 获取短剧 GID |
getDramaCardTitle(cardId) | 获取短剧标题 |
业务场景示例
信息流卡片
final config = DramaCardConfig(
dramaId: 12345,
width: 320,
isMuteDefault: true, // 默认静音,避免打扰
isAutoPlay: true, // 自动播放
isLooping: true, // 循环播放
hidePlayButton: true, // @ios 隐藏播放按钮
hideActionUI: true, // @ios 隐藏操作UI
hideSoundButton: true,// @android 隐藏声音按钮
);
final result = await PangrowthContent.createDramaCard(config);
沉浸式播放
final config = DramaCardConfig(
dramaId: 12345,
width: 375,
isMuteDefault: false, // 有声播放
isAutoPlay: true, // 自动播放
isLooping: false, // 不循环
hidePlayButton: false, // 保留播放控制
hideActionUI: false, // 保留操作UI
);
final result = await PangrowthContent.createDramaCard(config);
📡 事件监听
卡片生命周期及播放状态通过 DramaCardListener
监听:
可用回调:
onCardReady(String cardId)
- 卡片创建完成onDataLoaded(DramaInfo? drama)
- 短剧数据加载完成onCardClicked(DramaInfo? drama)
- 用户点击卡片onPlaybackStateChanged(bool isPlaying)
- 播放状态变化onCardError(String error)
- 卡片加载失败onCardDisposed()
- 卡片已销毁
🌍 平台差异
Android
- 卡片 View 由
IDJXElement
提供,可直接嵌入任意 ViewGroup - NativeView 方式:通过 PlatformView 嵌入
- API 方式:通过专用 Activity 托管全屏展示
width
以 dp 传入,高度自动按 16:9 计算
iOS
DJXPlayletCard
直接作为UIView
使用,天然支持嵌入- NativeView 方式:通过 PlatformView 嵌入
- API 方式:通过 ViewController 全屏弹出
width
参数自动计算 frame(x:0, y:0, width:width, height:width*9/16)- 设置
hideActionUI
后可自行叠加自定义 UI
💡 最佳实践
推荐使用 NativeView 方式
除非有特殊需求,否则推荐使用 DramaCardNativeView
,理由:
- ✅ 自动管理生命周期,减少内存泄漏风险
- ✅ 代码更简洁,符合 Flutter 开发习惯
- ✅ 与 Flutter Widget 树完美集成
- ✅ 支持
DramaCardController
和DramaCardListener
- ✅ 可直接嵌入信息流、网格等布局
配置参数选择建议
- 只传递需要修改的参数:SDK 会为未传递的参数使用原生默认值
- 信息流场景:
isMuteDefault: true
- 默认静音isLooping: true
- 循环播放hidePlayButton: true
/hideSoundButton: true
- 隐藏控件
- 详情页场景:
isMuteDefault: false
- 有声播放isLooping: false
- 不循环- 保留所有控件
性能优化建议
- 列表场景:配合
AutomaticKeepAliveClientMixin
避免重复创建 - 及时销毁:页面退出时确保 dispose
- 合理设置尺寸:建议宽度 > 180dp,保持 16:9 比例
错误处理
// NativeView方式
DramaCardNativeView(
config: config,
listener: DramaCardListener(
onCardError: (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('加载失败: $error')),
);
},
),
)
// API方式
try {
final result = await PangrowthContent.createDramaCard(config);
if (result['success'] != true) {
debugPrint('创建失败');
}
} catch (e) {
debugPrint('异常: $e');
}
🔗 相关文档
- 短剧聚合页 - 短剧列表展示和推荐
- 短剧播放页 - 单个短剧详情播放
- 短剧滑滑流 - 竖向滑动播放体验
- Widget组件总览 - 所有组件导航
💡 提示: 短剧卡片需要有效的短剧内容源。建议合理设置卡片尺寸(宽度 > 180dp)和播放参数(静音、循环)以获得最佳用户体验。