Flutter 提供了一个平台视图(Platform View)的概念。它提供了一种方法,允许开发者在 Flutter 里面嵌入原生系统(Android 和 iOS)的视图,并加入到 Flutter 的渲染树中,实现与 Flutter 一致的交互体验。
首先,由作为客户端的 Flutter,通过向原生视图的 Flutter 封装类(在 iOS 和 Android 平台分别是 UIKitView 和 AndroidView)传入视图标识符,用于发起原生视图的创建请求;
然后,原生代码侧将对应原生视图的创建交给平台视图工厂(PlatformViewFactory)实现;
最后,在原生代码侧将视图标识符与平台视图工厂进行关联注册,让 Flutter 发起的视图创建请求可以直接找到对应的视图创建工厂。
flutter 端代码
class DefaultPage extends StatefulWidget {
@override
StatecreateState()=>DefaultState();
}
class DefaultState extends State {
late NativeViewController controller;
@override
void initState() {
controller =NativeViewController();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor:Colors.yellowAccent,
appBar:AppBar(title:Text("Default Page")),
body:Center(
child:Container(width:200, height:200,
child:SampleView27(controller:controller)),
),
floatingActionButton:
FloatingActionButton(child:Icon(Icons.change_history),
onPressed: ()=>controller.changeBackgroundColor())
);
}
}
class SampleView extends StatefulWidget {
const SampleView({
Key ? key,
required this.controller,
}) :super(key: key);
final NativeViewController controller;
@override
StatecreateState() =>_SampleViewState();
}
class _SampleViewState extends State {
@override
Widget build(BuildContext context) {
if (defaultTargetPlatform ==TargetPlatform.android) {
return AndroidView(
viewType:'SampleView',
onPlatformViewCreated:_onPlatformViewCreated,
);
}else {
return UiKitView(viewType:'SampleView',
onPlatformViewCreated:_onPlatformViewCreated
);
}
}
_onPlatformViewCreated(int id)=>widget.controller.onCreate(id);
}
class NativeViewController {
late MethodChannel _channel;
onCreate(int id) {
print(id);
_channel =MethodChannel('samples.chenhang/native_views_$id');
}
changeBackgroundColor()async
{
_channel.invokeMethod('changeBackgroundColor');
}
}
iOS端代码
Info.plist 文件中增加一项配置
import Foundation
import Flutter
class PlatformTextViewFactory:NSObject,FlutterPlatformViewFactory {
var messenger:FlutterBinaryMessenger!
func create(withFrame frame:CGRect, viewIdentifier viewId: Int64, arguments args: Any?) ->FlutterPlatformView {
return PlatformTextView(frame,viewID:viewId,args: args, binaryMessenger: messenger)
}
func createArgsCodec(messenger: (NSObject&FlutterBinaryMessenger)?)-> FlutterMessageCodec&NSObjectProtocol {
returnFlutterStandardMessageCodec.sharedInstance()
}
@objc public init(messenger: (NSObject&FlutterBinaryMessenger)?) {
super.init()
self.messenger = messenger
}
}
import Foundation
import Flutter
import UIKit
class PlatformTextView:NSObject,FlutterPlatformView {
let frame:CGRect;
let viewId:Int64;
var text:String =""
var messenger:FlutterBinaryMessenger!
var _label = UILabel();
init(_ frame:CGRect,viewID: Int64,args :Any?, binaryMessenger: FlutterBinaryMessenger) {
self.frame = frame
self.viewId = viewID
self.messenger = binaryMessenger;
if(args is NSDictionary){
let dict = args as! NSDictionary
self.text = dict.value(forKey: "text") as! String
}
}
func initMethodChannel(){
letchannel = FlutterMethodChannel.init(name:"samples.chenhang/native_views_\(viewId)",binaryMessenger: messenger);
channel.setMethodCallHandler({ [self]
(call: FlutterMethodCall, result: FlutterResult) ->Void in
if(call.method =="changeBackgroundColor"){
_label.backgroundColor = UIColor.blue
print("-------")
result(0)
}else{
_label.backgroundColor = UIColor.red
result(FlutterMethodNotImplemented);
}
});
}
func view()-> UIView {
initMethodChannel()
print(self.text)
_label.text =self.text
_label.backgroundColor = UIColor.red
_label.textColor = UIColor.white
_label.frame =self.frame
return_label
}
}
override func application(
_ application:UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) ->Bool {
GeneratedPluginRegistrant.register(with:self)
let registrar = self.registrar(forPlugin: "samples.chenhang/native_views")
let messenger = registrar!.messenger() as! (NSObject & FlutterBinaryMessenger)
let factory = PlatformTextViewFactory(messenger:messenger)
registrar!.register(factory, withId: "SampleView")
return super.application(application, didFinishLaunchingWithOptions:launchOptions)
}
}
android 端代码
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.view.FlutterView;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;
import android.view.*;
import android.content.*;
import android.graphics.Color;
import io.flutter.plugin.common.MessageCodec;
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.common.BinaryMessenger;
import android.content.Intent;
import io.flutter.embedding.engine.FlutterEngine;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.shim.ShimPluginRegistry;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.StandardMessageCodec;
public class MainActivityextends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
ShimPluginRegistry shimPluginRegistry =new ShimPluginRegistry(flutterEngine);
GeneratedPluginRegistrant.registerWith(flutterEngine);
PluginRegistry.Registrar registrar = shimPluginRegistry.registrarFor("samples.chenhang/native_views");
SampleViewFactory playerViewFactory =new SampleViewFactory(registrar.messenger());
registrar.platformViewRegistry().registerViewFactory("SampleView", playerViewFactory);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
class SampleViewFactoryextends PlatformViewFactory {
private final BinaryMessenger messenger;
public SampleViewFactory(BinaryMessenger msger) {
super(StandardMessageCodec.INSTANCE);
messenger = msger;
}
@Override
public PlatformView create(Context context,int id, Object obj) {
return new SimpleViewControl(context, id, messenger);
}
}
class SimpleViewControlimplements PlatformView, MethodChannel.MethodCallHandler {
private final MethodChannel methodChannel;
private final View view;
public SimpleViewControl(Context context,int id, BinaryMessenger messenger) {
view =new View(context);
view.setBackgroundColor(Color.rgb(255,0,0));
methodChannel =new MethodChannel(messenger,"samples.chenhang/native_views_" + id);
methodChannel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
if (methodCall.method.equals("changeBackgroundColor")) {
view.setBackgroundColor(Color.rgb(0,0,255));
result.success(0);
}else {
result.notImplemented();
}
}
@Override
public View getView() {
return view;
}
@Override
public void dispose() {
}
}