flutter均分,flutter intent
Flutter与原生通信概述
flutter与原生通信主要有三种方式:MethodChannel、EventChannel、BasicMessageChannel,这三种方式均各有适用的场景:MethodChannel用于native与flutter的方法调用,EventChannel用于native单向的向flutter发送广播消息,BasicMessageChannel用于native与flutter之间的消息互发。
创新互联公司-专业网站定制、快速模板网站建设、高性价比栖霞网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式栖霞网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖栖霞地区。费用合理售后完善,十载实体公司更值得信赖。
MethodChannel用于双方之间的方法互调,使用步骤是:
1.创建一个MethodChannel对象,传入MethodChannel名称。
2.使用setMethodHandle对对方调用自己的方法进行监听,通过回调中的MethodCall对象方法名判断、获取方法参数,并且返回调用结果。
3.使用invokeMethod来调用对方的方法,可传入方法名,方法参数,以及监听对方的回调结果。
以下是示例:
需要注意的是,MethodChannel的名称需要双方保持一致,否则就不是同一个MethodChannel了。另外这里的方法调用并不是像Java里面反射那样去先找到class示例对象再解析到相应的方法,而是将双方互发的消息包装成了MethodCall对象,拿到这个对象后通过MethodCall里面的方法名去判断要做什么操作,并不是直接就调用了自身(native或flutter)相对应的方法。具体要做什么操作、调用什么方法还是得自己去调用和实现。
EventChannel适用于native向flutter发送广播消息,只是单向的消息发送,native发,flutter收,返过来flutter并不能向native发送消息。例如native可将定位数据不断的报给flutter,或者录像数据等等,所有基于原生能力产生的数据都可以通过EventChannel进行发送。
步骤:
1.创建一个EventChannel对象,传入EventChannel名称。
2.flutter端调用receiveBroadcastStream进行广播消息注册,传入arguments参数即为广播名称,此参数是告诉native端你要接受的广播类型,判别是什么广播发送的数据。
2.native调用setStreamHandler方法进行广播消息监听,onListen回调里会有一个arguments参数,这里及为flutter注册的广播类型,若flutter端没有注册,则native端不会收到这个回调,也就无法进行消息发送。收到flutter端的广播注册后,根据arguments可判断广播类型,然后根据EventChannel.EventSink来进行消息发送,EventSink.success()即可将消息发送给flutter端。
3.flutter进行广播注册会返回一个streamSubscription类型的对象,该对象可以进行消息的停止,native可在onCancel回调里面收到。
示例如下:
BasicMessageChannel就是比较常用的消息互发,使用步骤如下:
1.创建BasicMessageChannel对象,传入BasicMessageChannel名称。还需传入编解码方式(可以自己实现),系统提供了一些列的编解码方式,后续会介绍到。
2.使用setMessageHandler方法进行消息监听,也可进行回复。
3.使用send方法进行消息发送。
无论哪种方式的消息传递,最终都是将自定义数据转化为二进制数据进行传递,flutter提供的编解码方式分为MethodCodec和MessageCodec两种,EventChannel和MethodChannel使用的就是MethodCodec,BasicMessageChannel使用的是MessageCodec。MethodCodec其实就是在MessageCodec的基础上将数据包装了一下,使其转化为MethodCall对象方便使用。
MethodCodec源码:
MethodCodec提供了两种方式:JSONMethodCodec和StandardMethodCodec,前一种就是JSON和MethodCall对象之间的互转,后一种则是根据传入的数据基本类型(String,Integer等)来进行互转。
MessageCodec则提供了四种方式,如下图,具体就不详细讲述了,看看名字就知道是怎么回事,可以直接去看源码。最常用和默认的就是StandardMessageCodec方式。
从上面的使用方式可以看出,每一种Channel在创建的时候都需要传递一个BinaryMessenger,这个接口可以在FlutterEngine里面拿到,因此需要在FlutterActivity里面实现configFlutterEngine方法里面重写这个方法。FlutterActivity在attach FlutterEngine之后就会调用这个configFlutterEngine方法,通过flutterEngine.getPlugins().add(FlutterPlugin)方法可以FlutterPlugin的回调方法里进行数据的初始化和销毁工作。如下图
这个回调方法里的FlutterPluginBinding提供了一些我们可能会用到的对象,如下:
Flutter 与 iOS 原生 webView 对比
本文对比的是 UIWebView、WKWebView、flutter_webview_plugin(在iOS中使用的是WKWebView)的加载速度,内存使用情况。
测试网页打开的速度,只需要获取 WebView 在开始加载网页和网页加载完成时的时间戳,时间戳的差即为打开网页的时间
为了使差异更明显,我们选择较为复杂的 新浪首页 进行加载的对比,为了减小网络对加载速度的影响,我们让手机连接同一个网络,分别进行 10 次测试然后取平均值,另外,我们需要关闭 WebView 的缓存,防止缓存对加载速度产生影响
下面使笔者进行 10 次测试所得到的数据
结果让我有点惊讶,一直以为 WKWebView 会是个王者。结果看,速度上 WKWebView 略慢一点,不过总体差异不大(该结果仅仅是测试新浪的结果,仅供参考啦)
在这里,笔者又加了一个测试,尝试记录从 viewController 的 viewDidLoad 到 webview 的 didFinish 时间,测试了新浪的数据,如下:
UIWebViewA : 4970、3808、3815、4250、3556 avg(4079.8) (加载完所有页面)
UIWebViewB : 4103、3124、3070、3256、2835 avg(3277.6)(加载sina完毕)
WKWebView : 3672、3032、2892、2912、2739 avg(3049.4)
flutter_webView : 4532、3901、4310、3496、3378 avg(3923.4)
其中可以看到,webView 有两行,UIWebViewB 的数据就是加载 sina 主站的时间;UIWebViewA 的数据是因为在加载完 sina 主站之后,新浪又加载了一个 ,所以导致总时间延长,不过即使按照 UIWebViewB 的数据来比较,也是 wkWebView 略胜一筹。
此处可以看出 flutter_webView 使用的是 wkwebView,所以它吃亏的主要原因是 flutter 包了一层。
结论:
速度(didStart - didFinish) UIWebView flutter_webview WKWebView
速度(viewDidLoad - didFinish)WKWebView UIWebView flutter_webview
这里查看内存使用的是 xcode 的 debug session 中的 memory。
首先看之前测试时,连续打开十次新浪的内存情况
接着我们在看一下打开淘宝首页的内存情况
从图上可以看出,WKWebView 在内存方面有很大的优势啊,UIWebView 的内存是真的伤啊,然后 debug 看了一下 flutter_webView,他使用的就是原生的 webView 。
他相比较原生 WKWebView 的内存开销稍大一点,从测试表现来看,一般大个 30 MB 左右。
结论:内存 WKWebView flutter_webview UIWebView
可以在 html5test 中对浏览器的兼容性进行评分,通过测试发现得分分别如下
因为 flutter 里使用的就是 WK,所以和原生的 WKWebView 一样都是 444 分,比 UIWebView 的 437 略胜一筹
结论:兼容性 WKWebView = flutter_webview UIWebView
UIWebView : 速度相比较 WKWebView 稍快一点,但是内存是一大硬伤,所以只要条件允许,就不推荐使用了
WKWebView : 速度略慢一点,不过差别不大,总体可以接受。是比UIWebView更好的选择,推荐使用。
flutter_webView_plugin :在iOS中使用的就是原生的WKWebView,所以总体和 native WKWebView 表现差不多。如果是混编项目中,因为它被包了一层,所以页面加载上存在一定的劣势,所以混编项目中仍然推荐使用 WKWebView。不过如果从多端考虑、以及项目可迁移等,那么使用也未尝不可,就是维护成本要增加一些,需要维护两套 webView。这个就需要根据自己的情况自己取舍了。
Flutter开发--如何布局?
相对于iOS开发,Flutter的布局更具有灵活性,每个页面设计都不一样,相同页面可选择的布局方式也不一样,如果单纯的说应该如何去布局,我觉得不现实,大家可以参考下 Flutter官方的布局教程 。接下来,笔者,通过项目中的一个页面,来一步一步的拆解布局的流程。整个过程,基本上按照拆解、组件封装、具体布局这三步来的。
根据设计图,可以看出整体可以分成两部分,上面一部分是系统介绍模块,下面一部分是真正的登录内容,因为涉及到叠加,因此考虑用Stack;
系统介绍模块部分:整体也是涉及到叠加,考虑用Stack,分为四部分。最底部渐变色背景用一个contanier,无须指定位置,全视图扩展;载放logo图标在上一层,用Image。最后两个Text同级放在最上层。Image,Text各用Positioned包裹去指定位置。
登录内容模块是最外层是一个Contanier容器,去控制背景色和圆角。然后是一个Column元素,逐行排列。
第一行为Image,
第二行为Text,
第三行可以看成一个小Column,分两块进行布局
第四行可以看成一个小Column,分两块进行布局
第五行可以看作一个TextButton,
第六行可以看作一个Row,分三块进行布局
通过上面这样一步一步的分析后,基本上对大致的布局有了一个了解,最外层的控件大致选对(只要能实现的话,就是复杂度以及效率的问题),然后一步一步的拆解每一行的元素,如果有重复的或者觉得可以封装出来的部分,则进行下一步。
每一行的拆解,大致也是按照这个思路来进行,因此笔者在这里就不做讲解了。
在做到第三第四行的时候,发现这两个很相似,而且设计到一些交互逻辑,笔者就想对第三第四行的这种展示进行封装,觉得今后的布局可能会用到,因此在这一步,可以先把这一块儿抽离出一个控件。利用TextField来实现这种输入操作,具体的实现笔者不再详细的描述了。
经过这一步,整体的规划设计图已经有了,各个组件也都有了,接下来的工作就是组装了。
具体布局设计到一些细节的地方,例如整体Column的居中对齐(crossAxisAlignment)、间隔(Padding或Container包裹,笔者更喜欢用SizedBox占位)、居左居右居中(Align)、点击事件(GestureDetector)以及圆角(BorderRadius)等一些特殊情况。
像第六行row是放在底部的,就可以在第六行前面增加一个Spacer()去填充空白区域。
对文字颜色大小等,可以用TextStyle直接设置。
对于输入框的删除按钮,可以用Offstage这种Flutter特有的控制显示隐藏的控件。
Flutter(5):基础组件之Row/Column
Row:在水平方向上排列子widget的列表。
Column:在垂直方向上排列子widget的列表。
注意:这两个属于多子节点空间,可以将children排列成一行/一列,但是自身不带滚动属性,如果超出了一行,在debug下面则会显示溢出的提示。
MainAxisAlignment:主轴方向上的对齐方式,会对child的位置起作用,默认是start。
其中MainAxisAlignment枚举值:
center:将children放置在主轴的中心;
end:将children放置在主轴的末尾;
spaceAround:将主轴方向上的空白区域均分,使得children之间的空白区域相等,但是首尾child的空白区域为1/2;
spaceBetween:将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾child都靠近首尾,没有间隙;
spaceEvenly:将主轴方向上的空白区域均分,使得children之间的空白区域相等,包括首尾child;
start:将children放置在主轴的起点;
其中spaceAround、spaceBetween以及spaceEvenly的区别,就是对待首尾child的方式。其距离首尾的距离分别是空白区域的1/2、0、1。
MainAxisSize:在主轴方向占有空间的值,默认是max。
MainAxisSize的取值有两种:
max:根据传入的布局约束条件,最大化主轴方向的可用空间;
min:与max相反,是最小化主轴方向的可用空间;
CrossAxisAlignment:children在交叉轴方向的对齐方式,与MainAxisAlignment略有不同。
CrossAxisAlignment枚举值有如下几种:
baseline:在交叉轴方向,使得children的baseline对齐;
center:children在交叉轴上居中展示;
end:children在交叉轴上末尾展示;
start:children在交叉轴上起点处展示;
stretch:让children填满交叉轴方向;
TextDirection:阿拉伯语系的兼容设置,一般无需处理。
VerticalDirection:定义了children摆放顺序,默认是down。
VerticalDirection枚举值有两种:
down:从top到bottom进行布局;
up:从bottom到top进行布局。
top对应Row以及Column的话,就是左边和顶部,bottom的话,则是右边和底部。
TextBaseline:使用的TextBaseline的方式,有两种,前面已经介绍过。
这个是Row/Column的内的小控件,可以用来实现权重的布局
这边使用一个Container,里面是Row,使用Expanded对子节点进行权重处理,如果不使用Expanded,直接放入其他控件也是可以的,只是无法设置权重
对于内容过长的时候,会有溢出提示:
MainAxisAlignment.center:将children放置在主轴的中心;
MainAxisAlignment.start:将children放置在主轴的起点;
MainAxisAlignment.end:将children放置在主轴的末尾;
MainAxisAlignment.spaceAround:将主轴方向上的空白区域均分,使得children之间的空白区域相等,但是首尾child的空白区域为1/2;
MainAxisAlignment.spaceBetween:将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾child都靠近首尾,没有间隙;
MainAxisAlignment.spaceEvenly:将主轴方向上的空白区域均分,使得children之间的空白区域相等,包括首尾child;
下一章我们学习基础组件之Image
分享题目:flutter均分,flutter intent
文章起源:http://myzitong.com/article/dsssdij.html