【Flutter】PlatformViewの表示

実装手順

  • Dart
    • PlatFormViewの呼び出し
  • kotlin/Swift
    • 表示するViewの作成
    • 表示するViewのFactoryクラス作成
    • Pluginクラスの作成
    • Pluginの登録

Dart

PlatFormViewの呼び出し

class PlatformViewWidget extends StatelessWidget {
  const PlatformViewWidget({required this.text});

  final String text;

  @override
  Widget build(BuildContext context) {
    final param = {"text": text};
    // Platform側の実装と合わせる
    final viewType = "com.example.platform_view/plugin";
    if (Platform.isAndroid) {
      return AndroidView(
        viewType: viewType,
        layoutDirection: TextDirection.ltr,
        creationParams: param;
        creationParamsCodec: const StandardMessageCodec(),
      );
    } else if (Platform.isIOS) {
      return UiKitView(
        viewType: viewType,
        layoutDirection: TextDirection.ltr,
        creationParams: param;
        creationParamsCodec: const StandardMessageCodec(),
      );
    } else {
      return Container();
    }
  }
}

kotlin

表示するViewの作成

class MyAndroidView(context: Context?, messenger: BinaryMessenger, id: Int, creationParams: Map<String, String>): PlatformView {
  private val view: TextView

  init {
    view = TextView(context!!).apply {
      text = param["text"]
    }
  }

  override fun getView(): View {
    return view
  }

  override fun dispose() {}
}

表示するViewのFactoryクラス作成

class MyAndroidtViewFactory(private val messenger: BinaryMessenger) : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
    override fun create(context: Context?, id: Int, args: Any?): PlatformView {
        val creationParams = args as Map<String?, Any?>?
        return MyAndroidView(context, messenger, id, creationParams)
    }
}

Pluginクラスの作成

class MyAndroidViewPlugin: FlutterPlugin {
    override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        flutterPluginBinding.platformViewRegistry
            .registerViewFactory(
              "com.example.platform_view/plugin", // Dart側で指定した文字列を指定
              MyAndroidViewFactory(flutterPluginBinding.binaryMessenger) // 作成したFactoryクラスを指定
            )
    }

    override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {}
}

MainActivityでPluginの登録

class MainActivity: FlutterActivity() {
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine)
        flutterEngine.plugins.add(MyAndroidViewPlugin())
    }
}

Swift

表示するViewの作成

class MyUiKitView: NSObject, FlutterPlatformView {
    private var _view: UIView
    
    init(
        frame: CGRect,
        viewIdentifier viewId: Int64,
        arguments args: Any?,
        binaryMessenger messenger: FlutterBinaryMessenger?
    ) {
        _view = UIView()
        _view.backgroundColor = UIColor.white
        let label = UILabel()
        label.text = (arguments as! [String: String])["text"] label.textColor = UIColor.black
        label.textAlignment = .center
        label.frame = CGRect(x: 0, y: 0, width: 180, height: 48.0)
        _view.addSubview(label)
        super.init()
    }

    func view() -> UIView {
        return _view
    }
}

表示するViewのFactoryクラス作成

class MyUiKitViewFactory: NSObject, FlutterPlatformViewFactory {
    private var messenger: FlutterBinaryMessenger
    
    init(messenger: FlutterBinaryMessenger) {
        self.messenger = messenger
        super.init()
    }
    
    func create(
        withFrame frame: CGRect,
        viewIdentifier viewId: Int64,
        arguments args: Any?
    ) -> FlutterPlatformView {
        return MyUiKitView(
            frame: frame,
            viewIdentifier: viewId,
            arguments: args,
            binaryMessenger: messenger)
    }
    
    public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
        return FlutterStandardMessageCodec.sharedInstance()
    }
}

Pluginクラスの作成

class MyUiKitViewPlugin {
    public static func register(with registrar: FlutterPluginRegistrar) {
        // withIdにDart側で指定した文字列を指定
        registrar.register(
          MyUiKitViewFactory(messenger: registrar.messenger()),withId: "com.example.platform_view/plugin")
    }
}

AppDelegateでPluginの登録

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        // 作成したPluginクラスのregisterを呼び出す
        // forPluginに表示するNativeViewのクラス名を指定
        MyUiKitViewPlugin.register(with: self.registrar(forPlugin: "MyUiKitView")!)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}