Loading...
Loading...
Add a native view into your Flutter app
npx skill4agent add flutter/skills flutter-platform-viewsimport 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
Widget buildHybridAndroidView(BuildContext context, String viewType, Map<String, dynamic> creationParams) {
return PlatformViewLink(
viewType: viewType,
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: viewType,
layoutDirection: TextDirection.ltr,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
onFocus: () {
params.onFocusChanged(true);
},
)
..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
..create();
},
);
}import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Widget buildTextureAndroidView(BuildContext context, String viewType, Map<String, dynamic> creationParams) {
return AndroidView(
viewType: viewType,
layoutDirection: TextDirection.ltr,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
);
}MainActivitypackage dev.flutter.example
import android.content.Context
import android.graphics.Color
import android.view.View
import android.widget.TextView
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory
// 1. Define the View
internal class NativeView(context: Context, id: Int, creationParams: Map<String?, Any?>?) : PlatformView {
private val textView: TextView = TextView(context).apply {
textSize = 72f
setBackgroundColor(Color.rgb(255, 255, 255))
text = "Rendered on a native Android view (id: $id)"
}
override fun getView(): View = textView
override fun dispose() {}
}
// 2. Define the Factory
class NativeViewFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
val creationParams = args as Map<String?, Any?>?
return NativeView(context, viewId, creationParams)
}
}
// 3. Register in MainActivity
class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
flutterEngine
.platformViewsController
.registry
.registerViewFactory("<platform-view-type>", NativeViewFactory())
}
}SurfaceViewSurfaceTextureinvalidate()import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Widget buildIosView(BuildContext context, String viewType, Map<String, dynamic> creationParams) {
return UiKitView(
viewType: viewType,
layoutDirection: TextDirection.ltr,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
);
}import Flutter
import UIKit
// 1. Define the View
class FLNativeView: NSObject, FlutterPlatformView {
private var _view: UIView
init(frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?, binaryMessenger messenger: FlutterBinaryMessenger?) {
_view = UIView()
super.init()
createNativeView(view: _view)
}
func view() -> UIView { return _view }
func createNativeView(view _view: UIView){
_view.backgroundColor = UIColor.blue
let nativeLabel = UILabel()
nativeLabel.text = "Native text from iOS"
nativeLabel.textColor = UIColor.white
nativeLabel.textAlignment = .center
nativeLabel.frame = CGRect(x: 0, y: 0, width: 180, height: 48.0)
_view.addSubview(nativeLabel)
}
}
// 2. Define the Factory
class FLNativeViewFactory: 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 FLNativeView(frame: frame, viewIdentifier: viewId, arguments: args, binaryMessenger: messenger)
}
public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
return FlutterStandardMessageCodec.sharedInstance()
}
}
// 3. Register in AppDelegate
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
guard let pluginRegistrar = self.registrar(forPlugin: "plugin-name") else { return false }
let factory = FLNativeViewFactory(messenger: pluginRegistrar.messenger())
pluginRegistrar.register(factory, withId: "<platform-view-type>")
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Widget buildMacOsView(BuildContext context, String viewType, Map<String, dynamic> creationParams) {
return AppKitView(
viewType: viewType,
layoutDirection: TextDirection.ltr,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
);
}import Cocoa
import FlutterMacOS
// 1. Define the View
class NativeView: NSView {
init(viewIdentifier viewId: Int64, arguments args: Any?, binaryMessenger messenger: FlutterBinaryMessenger?) {
super.init(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
wantsLayer = true
layer?.backgroundColor = NSColor.systemBlue.cgColor
createNativeView(view: self)
}
required init?(coder nsCoder: NSCoder) { super.init(coder: nsCoder) }
func createNativeView(view _view: NSView) {
let nativeLabel = NSTextField()
nativeLabel.frame = CGRect(x: 0, y: 0, width: 180, height: 48.0)
nativeLabel.stringValue = "Native text from macOS"
nativeLabel.isEditable = false
nativeLabel.sizeToFit()
_view.addSubview(nativeLabel)
}
}
// 2. Define the Factory
class NativeViewFactory: NSObject, FlutterPlatformViewFactory {
private var messenger: FlutterBinaryMessenger
init(messenger: FlutterBinaryMessenger) {
self.messenger = messenger
super.init()
}
func create(withViewIdentifier viewId: Int64, arguments args: Any?) -> NSView {
return NativeView(viewIdentifier: viewId, arguments: args, binaryMessenger: messenger)
}
public func createArgsCodec() -> (FlutterMessageCodec & NSObjectProtocol)? {
return FlutterStandardMessageCodec.sharedInstance()
}
}
// 3. Register in MainFlutterWindow.swift
class MainFlutterWindow: NSWindow {
override func awakeFromNib() {
let registrar = flutterViewController.registrar(forPlugin: "plugin-name")
let factory = NativeViewFactory(messenger: registrar.messenger)
registrar.register(factory, withId: "<platform-view-type>")
super.awakeFromNib()
}
}flutter_bootstrap.js_flutter.loader.load({
onEntrypointLoaded: async function onEntrypointLoaded(engineInitializer) {
let engine = await engineInitializer.initializeEngine({
multiViewEnabled: true, // Enables embedded mode.
});
let app = await engine.runApp();
// Add a view to a specific host element
let viewId = app.addView({
hostElement: document.querySelector('#flutter-host-element'),
initialData: { greeting: 'Hello from JS!' }
});
}
});main.dartrunWidgetrunApprunAppimplicitViewimport 'dart:ui' show FlutterView;
import 'package:flutter/widgets.dart';
void main() {
// MUST use runWidget, not runApp, for multi-view web embedding.
runWidget(
MultiViewApp(
viewBuilder: (BuildContext context) => const MyEmbeddedWidget(),
),
);
}
class MultiViewApp extends StatefulWidget {
const MultiViewApp({super.key, required this.viewBuilder});
final WidgetBuilder viewBuilder;
State<MultiViewApp> createState() => _MultiViewAppState();
}
class _MultiViewAppState extends State<MultiViewApp> with WidgetsBindingObserver {
Map<Object, Widget> _views = <Object, Widget>{};
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_updateViews();
}
void didChangeMetrics() {
_updateViews();
}
void _updateViews() {
final Map<Object, Widget> newViews = <Object, Widget>{};
for (final FlutterView view in WidgetsBinding.instance.platformDispatcher.views) {
final Widget viewWidget = _views[view.viewId] ?? _createViewWidget(view);
newViews[view.viewId] = viewWidget;
}
setState(() {
_views = newViews;
});
}
Widget _createViewWidget(FlutterView view) {
return View(
view: view,
child: Builder(builder: widget.viewBuilder),
);
}
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
Widget build(BuildContext context) {
return ViewCollection(views: _views.values.toList(growable: false));
}
}
class MyEmbeddedWidget extends StatelessWidget {
const MyEmbeddedWidget({super.key});
Widget build(BuildContext context) {
// Retrieve the viewId to handle specific logic if needed
final int viewId = View.of(context).viewId;
return Directionality(
textDirection: TextDirection.ltr,
child: Center(child: Text('Rendered in View ID: $viewId')),
);
}
}runApprunWidgetFlutterViewWidgetsBindingObserverShaderMaskColorFilteredBackdropFilterSurfaceViewSurfaceTextureinvalidate()