继续创造,加速成长!这是我参加「日新方案 6 月更文应战」的第24天,点击检查活动详情
- 本文首要介绍Flutter学习之原生客户端交互,首要是在flutter运用iOS中的view。
1. 创立iOS工程View在Flutter中展示
咱们想要在flutter运用iOS中的view,应该怎么交互呢。咱们运用Xcode翻开咱们的Runner.xcworkspace
咱们在 iOS工程中创立一个测试view
import UIKit
import Flutter
class TestView:NSObject, FlutterPlatformView{
lazy var nameLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 15)
label.textColor = .white
// label.backgroundColor = .red
label.textAlignment = .center
return label
}()
init(_ frame: CGRect,viewID: Int64,args :Any?,messenger :FlutterBinaryMessenger) {
super.init()
nameLabel.text = "我是 iOS Test View"
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func view() -> UIView {
return nameLabel
}
}
同时创立TestViewFactory
import UIKit
import Flutter
class TestViewFactory:NSObject, FlutterPlatformViewFactory {
var messenger: FlutterBinaryMessenger
init(messenger:FlutterBinaryMessenger) {
self.messenger = messenger
super.init()
}
func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
return TestView(frame,viewID: viewId,args: args,messenger: messenger)
}
func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
return FlutterStandardMessageCodec.sharedInstance()
}
}
完成FlutterPlatformViewFactory
的协议办法,回来咱们的TestView
目标,经过完成协议办法进行交互。
import UIKit
import Flutter
class TestViewFactory:NSObject, FlutterPlatformViewFactory {
var messenger: FlutterBinaryMessenger
init(messenger:FlutterBinaryMessenger) {
self.messenger = messenger
super.init()
}
func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
return TestView(frame,viewID: viewId,args: args,messenger: messenger)
}
func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {
return FlutterStandardMessageCodec.sharedInstance()
}
}
咱们在delegate
中进行注册,进行通讯。
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
let registrar:FlutterPluginRegistrar = self.registrar(forPlugin: "plugins.flutter.io/custom_platform_view_plugin")!
let factory = TestViewFactory(messenger: registrar.messenger())
registrar.register(factory, withId: "plugins.flutter.io/custom_platform_view")
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
咱们在flutter项目中创立一个展示的页面
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
class IosViewPage extends StatelessWidget {
const IosViewPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
String? title = Get.arguments['title'];
return Scaffold(
appBar: AppBar(title: Text(title ?? ''),),
body: Center(
child:iosView(),
),
);
}
Widget iosView() {
if(defaultTargetPlatform == TargetPlatform.iOS){
return const UiKitView(
viewType: 'plugins.flutter.io/custom_platform_view',
creationParams: {'text': 'Flutter传给IOSTextView的参数'},
creationParamsCodec: StandardMessageCodec(),
);
}else {
return Container();
}
}
}
显现效果如下:
2. Flutter向ios传值
咱们在flutter页面中传一些参数
return const UiKitView(
viewType: 'plugins.flutter.io/custom_platform_view',
creationParams: {'text': 'Flutter传给IOSLabel的参数'},
creationParamsCodec: StandardMessageCodec(),
);
这里viewType
就是咱们注册的时分运用的标识符
。creationParams
为创立iOS view时带的参数
。creationParamsCodec
:将 creationParams
编码后再发送给平台侧,它应该与传递给构造函数的编解码器匹配
。
咱们在iOS项目中判断是否传递了参数
init(_ frame: CGRect,viewID: Int64,args :Any?,messenger :FlutterBinaryMessenger) {
super.init()
if args is NSDictionary {
let dict = args as! NSDictionary
nameLabel.text = dict.value(forKey: "text") as? String
}else{
nameLabel.text = "这是一个 iOS view"
}
}
运行结果
咱们在运行中经过按钮点击改动iOS View的内容
static const platform = MethodChannel('com.flutter.test.TestView');
咱们在flutter页面定义一个办法通道
RaisedButton(
child: const Text('传递参数给原生View'),
onPressed: () {
platform.invokeMethod('userInfo', {'name': 'Jack', 'city': "New York"});
},
点击的时分传参给iOS页面
let method = FlutterMethodChannel(name: "com.flutter.test.TestView", binaryMessenger: messenger)
method.setMethodCallHandler { (call, reslut) in
if (call.method == "userInfo") {
let dict: Dictionary? = call.arguments as? Dictionary<String, Any>
self.nameLabel.text = "my Name is:\(dict?["name"] ?? "")\n from:\(dict?["city"] ?? "")"
}
}
在页面中设置回调处理
,判断办法获取参数,进行展示
设置回调的时分还有一个result
没有运用,这个是用于咱们原生页面向flutter
传参运用的。
let method = FlutterMethodChannel(name: "com.flutter.test.TestView", binaryMessenger: messenger)
method.setMethodCallHandler { (call, reslut) in
if (call.method == "userInfo") {
let dict: Dictionary? = call.arguments as? Dictionary<String, Any>
self.nameLabel.text = "my Name is:\(dict?["name"] ?? "")\n from:\(dict?["city"] ?? "")"
}else if (call.method == "callBack") {
reslut(["title": self.nameLabel.text])
}
}
这里咱们运用reslut进行回传
,在flutter
中页面进行调用
RaisedButton(
child: Text(callbackData),
onPressed: () async {
var result = await IosViewPage.platform.invokeMethod('callBack');
setState((){
callbackData = '${result['title']}';
});
},
),
咱们进行回调显现咱们iOS中view的label文字到按钮上
3. 多个原生View通讯抵触问题
当咱们的页面有多个原生view,他们的通讯
怎么区别
。
当咱们点击的时分发现只要最好一个view产生改动,咱们如何改动。可以从2个方面,一个让这个办法变成唯一
的。将一个唯一 id
经过初始化参数传递给原生 View,原生 View运用这个id
构建不同称号的MethodChannel
。或者是经过viewID,原生 View 生成时,体系会为其生成唯一id:viewId
,运用 viewId 构建不同称号的MethodChannel
。
let method = FlutterMethodChannel(name: "com.flutter.test.TestView\(viewID)", binaryMessenger: messenger)
咱们在原生iOS的view中FlutterMethodChannel的name拼接viewID
var iosViews = [];
return UiKitView(
viewType: 'plugins.flutter.io/custom_platform_view',
creationParams: const {'text': 'Flutter传给IOSLabel的参数'},//初始值
creationParamsCodec: const StandardMessageCodec(),
onPlatformViewCreated: (viewID) => iosViews.add(MethodChannel('com.flutter.test.TestView$viewID')),
);
运用的时分取出对应的办法即可
终究结果
4. 小结
Flutter中嵌入原生iOS视图,首要经过flutter中的UiKitView
进行获取原生工程APPDelegate
中注册的FlutterPlatformView
类型从而获取加载到flutter页面。flutter和原生页面交互经过FlutterMethodChannel
,根据一些key, method
办法等进行交互回调函数的彼此回调完成通讯
。