如何在Flutter中动态创建基于PlatformViewLink的Android原生视图列表?
解决动态创建多个PlatformViewLink实例的问题
核心原理
registerViewFactory注册的是视图类型,而非单个视图实例——同一个类型ID可以创建多个独立的原生视图实例,关键在于Dart层要给每个Widget分配唯一的viewId。
具体实现步骤
1. 确保Android端ViewFactory支持多实例创建
你的MyViewFactory无需修改,它本身就是用来生成多个视图实例的,每次Dart请求创建视图时,create方法都会被调用生成新的原生View:
class MyViewFactory(private val messenger: BinaryMessenger) : PlatformViewFactory(StandardMessageCodec.INSTANCE) { override fun create(context: Context, viewId: Int, args: Any?): PlatformView { // 每个viewId对应一个独立的原生View实例 return MyNativeView(context, messenger, viewId) } }
注册操作只需在Activity启动时执行一次,无需重复注册:
// 在FlutterActivity的configureFlutterEngine方法中完成注册 override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) flutterEngine.platformViewsController.registry.registerViewFactory("myViewTypeId", MyViewFactory(flutterEngine.dartExecutor.binaryMessenger)) }
2. Dart层动态管理视图列表与唯一viewId
用StatefulWidget维护动态列表,为每个新视图分配唯一viewId,实现增删功能:
class NativeViewList extends StatefulWidget { const NativeViewList({super.key}); @override State<NativeViewList> createState() => _NativeViewListState(); } class _NativeViewListState extends State<NativeViewList> { final List<int> _viewIds = []; int _nextViewId = 1; // 从1开始,避免与系统默认ID冲突 // 添加新原生视图 void _addNativeView() { setState(() { _viewIds.add(_nextViewId); _nextViewId++; }); } // 移除指定位置的原生视图 void _removeNativeView(int index) { setState(() { _viewIds.removeAt(index); }); } @override Widget build(BuildContext context) { return Column( children: [ ElevatedButton( onPressed: _addNativeView, child: const Text('添加原生视图'), ), Expanded( child: ListView.builder( itemCount: _viewIds.length, itemBuilder: (context, index) { return ListTile( title: _NativeViewWidget(viewId: _viewIds[index]), trailing: IconButton( icon: const Icon(Icons.delete), onPressed: () => _removeNativeView(index), ), ); }, ), ), ], ); } } // 封装单个原生视图Widget class _NativeViewWidget extends StatelessWidget { final int viewId; const _NativeViewWidget({required this.viewId}); @override Widget build(BuildContext context) { return PlatformViewLink( viewType: 'myViewTypeId', // 与Android端注册的类型ID保持一致 surfaceFactory: (context, controller) { return AndroidViewSurface( controller: controller as AndroidViewController, gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{}, hitTestBehavior: PlatformViewHitTestBehavior.opaque, ); }, onCreatePlatformView: (params) { return PlatformViewsService.initSurfaceAndroidView( id: params.id, viewType: 'myViewTypeId', layoutDirection: TextDirection.ltr, creationParams: {}, // 如需给原生传递参数,可在此处设置 creationParamsCodec: const StandardMessageCodec(), ) ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated) ..create(); }, ); } }
3. 关键注意事项
- 每个
PlatformViewLink必须使用唯一的viewId,原生端通过viewId区分不同的视图实例。 viewFactory只需注册一次,重复注册会覆盖原有配置,但完全没必要——同一个工厂可创建任意多个实例。- 若需给每个原生视图传递不同参数,可在
creationParams中传入,原生端create方法通过args接收即可。
内容的提问来源于stack exchange,提问作者roon
相关产品推荐
相关产品推荐

