flutter插件基础之调用原生界面和flutter组件互相显示功能(四)

前几篇我们对flutter中的数据的传递层MethodChannel和监听响应层EventChannel进行了全面的介绍和案例展示,本篇

开始讲解flutter中如何显示原生View,如Android 中的AndroidView的显示和iOS中的UiKitView的显示过程

像小孩一样愉快的嗨起来.jpg

来吧,开始~~~展示!

四.flutter代码中显示原生View

1.显示原生View的原理说明

1.1.AndroidView和UiKitView

顾名思义,flutter为了兼容原生的安卓View在flutter中显示用AndroidView来统一替代所有需要显示在flutter中的安卓view,iOS同理用的是UiKitView,简单来说,这里的AndroidView和UiKitView相当于是原生的一个小仓库,所有的原生view都必须转换为flutter对应的AndroidView或UiKitView,至于具体的比如UiKitView有什么功能,比如UILable,UIButton则依赖于原生自身的特性决定其功能。

1.2.唯一标识key值的设定

同前面我们讲的MethodChannel和EventChannel调用机制,即通过唯一标识符在App启动页或者原生插件页中一开始进行相应的注册操作,然后在flutter中对其绑定同样的key,如此可根据key的一致性,来找到原生和flutter的调用入口,同理这里的原生View展示在flutter的流程也需要保持唯一标识key的统一。

如下所示为flutter代码中对安卓和iOS设置的key值为native_view_show字符标记。

**const** String viewType = **'native_view_show'**;

*// print("tempcreationParams = $tempcreationParams");*

**return** Container(

 width: ScreenUtils.*getScreeenWidth*(context),

 height: ScreenUtils.*getScreeenHeidth*(context),

 alignment: Alignment.*center*,

 color: Colors.*white*,

 child: defaultTargetPlatform == TargetPlatform.**android** ? AndroidView(

 viewType: viewType,

 layoutDirection: TextDirection.**ltr**,

 creationParams: {

 **"key"**: **"~~native-android"**,

 },

 creationParamsCodec: **const** StandardMessageCodec(),

 ) : UiKitView(

 viewType: viewType,

 layoutDirection: TextDirection.**ltr**,

 creationParams: {

 **"key"**: **"~~native-iOS"**,

 },

 creationParamsCodec: **const** StandardMessageCodec(),

 ),

);

如下为以安卓为例的原生类FlutterPluginDemo2Plugin.java中加入需要注册原生界面时标记该key的代码如下所示,在页面启动页的onAttachedToEngine 方法中

*//* 注册原生插件类

flutterPluginBinding

 .getPlatformViewRegistry()

 .registerViewFactory(**"native_view_show"**, **new** NativeViewFactory());

1.3.原生端的工厂类创建

同上所示,在一开始注册原生插件的时候,需要创建NativeViewFactory.java类,继承自PlatformViewFactory类,在该类里面初始化创建NativeView.java类,继承自PlatformView类,之后在工厂类里面创建NativeView.java类,在NativeView.java类里面对要展示的view进行基本初始化和功能操作。

如此即可实现最终在如安卓的NativeView.java中显示的view功能显示到flutter代码中。

2.同原生代码交互示例

在前面我们对flutter中显示原生的原理进行研究说明后,接下来我们将以最简单的原生组件如何顺利展示在flutter中,进行案例讲解。

那么,首先上场的是安卓端同flutter的交互展示。

2.1.安卓的显示与传值

2.1.1.Flutter端

在example/lib/show_native_page.dart类中在build方法中返回 AndroidView 代码如下所示

AndroidView(

 viewType: viewType,

 layoutDirection: TextDirection.**ltr**,

 creationParams: {

 **"key"**: **"~~native-android"**,

 },

 creationParamsCodec: **const** StandardMessageCodec(),

)

其中这里的viewType是定义同安卓交互的唯一字符串标识如下

**const** String viewType = **'native_view_show'**;

2.1.2.Native(Android)端

1.在原生安卓端的FlutterPluginDemo2Plugin.java,类中的onAttachedToEngine方法中提前注册好原生插件NativeViewFactory工厂类;

*//* 注册原生插件类

flutterPluginBinding

 .getPlatformViewRegistry()

 .registerViewFactory(**"native_view_show"**, **new** NativeViewFactory());

2.工厂类NativeViewFactory.java中初始化加入NativeView.java类

代码如下所示:

**class** NativeViewFactory **extends** PlatformViewFactory {

 NativeViewFactory() {

 **super**(StandardMessageCodec.INSTANCE);

 }

 @NonNull

 @Override

 **public** PlatformView create(@NonNull Context context, **int** id, @Nullable Object args) {

 **final** Map creationParams = (Map) args;

 Log.d(**"creationParams"**, creationParams.toString());

*// System.out.print(creationParams);*

**return new** NativeView(context, id, creationParams);

 }

}

3.在NativeView.java类中自定义安卓的view(如示例所示为一段textView对象居中显示效果),

安卓View显示到flutter.jpeg

如此就可以通过以上方法把安卓的TextView正确显示在flutter的界面上,实现我们的目标。

2.2.iOS的显示与传值

2.2.1.Flutter端

同安卓端所示,在 example/lib/show_native_page.dart类中在build方法中返回 UiKitView 代码所示

UiKitView(

 viewType: viewType,

 layoutDirection: TextDirection.**ltr**,

 creationParams: {

 **"key"**: **"~~native-iOS"**,

 },

 creationParamsCodec: **const** StandardMessageCodec(),

)

2.2.2.Native(iOS)端

同安卓端类似,iOS的原生端流程可以简单概括为,

工厂类的注册——>工厂类的初始化创建——>原生iOSView的展示

1.工厂类的注册

在iOS的 FlutterPluginDemo2Plugin.m类的 registerWithRegistrar方法中提前注册好工厂类FlutterNativeFactory,保证是同flutter的唯一标识字符串相同,如下为native_view_show

FlutterNativeFactory* factory =

 [[FlutterNativeFactory alloc] initWithMessenger:registrar.messenger];

 [registrar registerViewFactory:factory withId:**@"native_view_show"**];

2.工厂类的初始化创建
在FlutterNativeFactory.h类中遵循FlutterPlatformViewFactory协议,实现其createWithFrame方法,如下所示

- (NSObject*)createWithFrame:(CGRect)frame

 viewIdentifier:(int64_t)viewId

 arguments:(id **_Nullable**)args {

 **return** [[FlutterNativeView alloc] initWithFrame:frame

 viewIdentifier:viewId

 arguments:args

 binaryMessenger:_messenger];

}

在FlutterNativeFactory.m类中设置初始化入口initWithMessenger方法,供FlutterPluginDemo2Plugin.m类使用

3.原生iOS的View的展示

在原生的FlutterNativeView类中的initWithFrame方法中初始化iOS的view,通过以上的流程顺利展示在flutter界面上

- (instancetype)initWithFrame:(CGRect)frame

 viewIdentifier:(int64_t)viewId

 arguments:(id **_Nullable**)args

 binaryMessenger:(NSObject*)messenger {

 **if** (self = [super init]) {

 _view = [[UIView alloc] init];

*// double kScreenW =* [*UIScreen mainScreen*]*.bounds.size.width;*

*// double kScreenH =* [*UIScreen mainScreen*]*.bounds.size.height;*

_view.frame = CGRectMake(0, 200, 200, 200);

 _view.backgroundColor = [UIColor redColor];

 NSLog(**@"args = %@"**,args);

 **if** ([args isKindOfClass:[NSDictionary **class**]]) {

 NSString *key = args[**@"key"**];

 NSLog(**@"key = %@"**);

 _nameLable.text = [NSString stringWithFormat:**@"%@%@%@"**,**@"我是"**,key,**@"的UILabel"**];

 }

 [_view addSubview:self.nameLable];

 }

 **return** self;

}

3.注意事项细节

3.1.唯一标识key的统一

虽然有点啰嗦,但仍需要再次说明,即在example/lib/show_native_page.dart类中设置viewType的值

**const** String viewType = **'native_view_show'**;

要和如下所示(以安卓为例)的FlutterPluginDemo2Plugin.java类中的onAttachedToEngine方法注册的插件view工厂类的key保持一致

*//* 注册原生插件类

flutterPluginBinding

 .getPlatformViewRegistry()

 .registerViewFactory(**"native_view_show"**, **new** NativeViewFactory());

3.2.传值问题

如下所示为安卓的AndroidView中的creationParams属性可以设置flutter要传递给原生的内容,在经过层层传递后可以实现在安卓的NativeView.java类的构造方法中获取到传递的内容为creationParams对象,从而展示在原生的TextView对象身上。

NativeView(@NonNull Context context, **int** id, @Nullable Map creationParams) {

 String value = creationParams.get(**"key"**).toString();

 **textView** = **new** TextView(context);

 **textView**.setTextSize(30);

 **textView**.setBackgroundColor(Color.rgb(255, 255, 255));

 **textView**.setGravity(Gravity.CENTER);

 **textView**.setText(**"show Android view (原生接收到的值为: "** + value + **")"**);

}

3.3.iOS原生界面展示细节说明

需要注意的是在iOS中的最外层界面展示尺寸方面,仅对位置定义有用,对尺寸设置是没用的,会默认铺满剩余空间,所以如下所示为安卓的最外层界面展示内容:

_view.center = CGPointMake(200, 150);

 _view.bounds = CGRectMake(0, 0, 100, 100);

 _view.backgroundColor = [UIColor redColor];

而对_view的subview如nameLable并没有影响,可以正常按照iOS的规则进行相关设置操作

 **self**.nameLable.frame = CGRectMake(0, 100, 200, 50);

 **self**.nameLable.backgroundColor = [UIColor blueColor];

 [_view addSubview:**self**.nameLable];

简而言之,即为设置原生最外层尺寸时,仅设置其定位位置,如frame的前2项x和y或者是center对象,而对其尺寸方面的设置是无效的,因为它会默认铺满剩余尺寸,但是对该view的子view设置尺寸按照正常的iOS规则是可以生效的。

这是按照上面设置父View和子View后的效果如下所示,安卓是不是遵循同样的规则,还请小伙伴们自行验证哈。

iOSView在flutter上的显示.png

好了,经过前面的研究和分析,我们对flutter同原生的数据层交互的MethodChannel,EventChannel,以及界面层交互的AndroidView 和 UiKitView的基础使用基本掌握,并且对二者交互的原理得到进一步的了解,这里附上在此系列中写的所有代码的一个小案例,以饷食者!

Flutter同原生交互案例展示:flutter同原生交互Demo示例

下一篇我们将逐步尝试从简单编写一个小插件,小插件的本地,远程发布,以及如何使用的流程进行整体的说明,从而让大家都能编写好自己的小插件,尽可能的解决更多flutter解决不了的原生问题,提供开发速度。
flutter插件基础之调用EventChannel的简单使用(三)

好了,本篇完~~

你可能感兴趣的:(flutter插件基础之调用原生界面和flutter组件互相显示功能(四))