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<String, Object> creationParams = (Map<String, Object>) 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<FlutterPlatformView>*)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<FlutterBinaryMessenger>*)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<String, Object> 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的简单使用(三)

好了,本篇完~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容