You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 20:10:49