重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
页面中的各界面元素(Widget)以树的形式组织,即控件树。Flutter通过控件树中的每个控件创建不同类型的渲染对象,组成渲染对象树。而渲染对象树在Flutter的展示过程分为三个阶段:布局、绘制、合成和渲染。
成都创新互联服务项目包括化德网站建设、化德网站制作、化德网页制作以及化德网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,化德网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到化德省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
(一)布局
Flutter采用深度优先机制遍历渲染对象树,决定渲染对象树中各渲染对象在屏幕上的位置和尺寸。在布局过程中,渲染对象树中的每个渲染对象都会接收父对象的布局约束参数,决定自己的大小,然后父对象按照控件逻辑决定各个子对象的位置,完成布局过程。
为了防止因子节点发生变化而导致整个控件树重新布局,Flutter加入了一个机制——布局边界(Relayout Boundary),可以在某些节点自动或手动地设置布局边界,当边界内的任何对象发生重新布局时,不会影响边界外的对象,反之亦然。
二)绘制
布局完成后,渲染对象树中的每个节点都有了明确的尺寸和位置。Flutter会把所有的渲染对象绘制到不同的图层上。与布局过程一样,绘制过程也是深度优先遍历,而且总是先绘制自身,再绘制子节点。
以下图为例:节点1在绘制完自身后,会再绘制节点2,然后绘制它的子节点3、4和5,最后绘制节点6。
可以看到,由于一些其他原因(比如,视图手动合并)导致2的子节点5与它的兄弟节点6处于了同一层,这样会导致当节点2需要重绘的时候,与其无关的节点6也会被重绘,带来性能损耗。
为了解决这一问题,Flutter提出了与布局边界对应的机制——重绘边界(Repaint Boundary)。在重绘边界内,Flutter会强制切换新的图层,这样就可以避免边界内外的互相影响,避免无关内容置于同一图层引起不必要的重绘。
重绘边界的一个典型场景是Scrollview。ScrollView滚动的时候需要刷新视图内容,从而触发内容重绘。而当滚动内容重绘时,一般情况下其他内容是不需要重绘的,这时候重绘边界就派上用场了。
(三)合成和渲染
终端设备的页面越来越复杂,因此Flutter的渲染树层级通常很多,直接交付给渲染引擎进行多图层渲染,可能会出现大量渲染内容的重复绘制,所以还需要先进行一次图层合成,即将所有的图层根据大小、层级、透明度等规则计算出最终的显示效果,将相同的图层归类合并,简化渲染树,提高渲染效率。
合并完成后,Flutter会将几何图层数据交由Skia引擎加工成二维图像数据,最终交由GPU进行渲染,完成界面的展示。
四、总结
咱们从各种业界主流跨端方案与Flutter的对比开始,到Flutter的简要介绍以及Flutter的运行机制,并以界面渲染过程为例,从布局、绘制、合成和渲染三个阶段讲述了Flutter的实现原理。相信大家对Flutter已经有一个整体认知,赶快一起上手操作起来吧!
抽象类Element 有mount方法
抽象类Widget 有createElement方法
RenderObjectWidget有createElement方法 和 createRenderObject方法
每一个Widget, 都有createElement方法,通过createElement方法 创建一个Element对象,
Element加入Element树中,它会创建三种Element ,每个Element 有个mount方法
第一种:RenderObjectElement(RenderObjectWidget的createElement方法)
mount方法中 调用
widget.createRenderObject(this) ,创建RenderObject对象,RenderObject对象加入Render树中
第二种:StatefulElement继承ComponentElement
第三种:StatelessElement继承ComponentElement
并不是所有的Widget都会被独立渲染!只有继承RenderObjectWidget的才会创建RenderObject对象!
ChangeNotifierProvider、ChangeNotifier、Consumer的关系
1、ChangeNotifierProvider的父类ListenableProvider,ListenableProvider中实现了_startListening方法,_startListening主要是将Element的刷新方法添加到ChangeNotifier中的_listeners中
2、ListenableProvider将startListening传入其父类InheritedProvider,InheritedProvider主要是创建delegate = _CreateInheritedProvider。这个delegate就是_CreateInheritedProvider中delegate.startListening中的delegate
1、ChangNotifier负责更新UI
ChangeNotifier中notifyListeners,通过遍历_listeners,实现强制刷新UI
1、Consumer:包裹待刷新UI,在buildWithChild中将Provider.ofT(context)传入builder方法
2、解析 Provider.ofT(context)
Provider.ofT(context)是获取ChangeNotifier对象的方法
Provider.of中通过传入的context,获取父视图为inheritedElement的对象
获取到inheritedElement,通过inheritedElement.getValue的方式获取ChangeNotifier对象
7、继续查看inheritedElement?.value。通过断点可以进入_CreateInheritedProvider 类中get Value方法。调用startListening将当前Consumer包裹的element添加到Prorivder的_listeners数组中
通过调用notifyListeners()来刷新所有Consumer完整的Provider执行流程大概就是这样,流程图如下
1.环境准备, 参考链接
2.添加国内环境配置: 参考链接
3.新建
name: String类型,代表Channel的名字,也是其唯一标识符。
messager:BinaryMessenger类型,代表消息信使,是消息的发送与接收的工具。
codec: MessageCodec类型或MethodCodec类型,代表消息的编解码器。
fluuter中的MessageCodec用于二进制格式数据与基础数据之间的编解码。BasicMessageChannel所使用的编解码器就是MessageCodec。
iOS中,名称为FlutterMessageCodec,是一个协议,定义了两个方法:encode接收一个类型为id的消息,将其编码为NSData类型,而decode接收NSData类型消息,将其解码为id类型数据。
MessageCodec有多种不同的实现:
与MessageCodec不同的是,MethodCodec用于MethodCall对象的编解码,一个MethodCall对象代表一次从Flutter端发起的方法调用。MethodCall有2个成员变量:String类型的method代表需要调用的方法名称,通用类型(Android中为Object,iOS中为id)的arguments代表需要调用的方法入参
由于处理的是方法调用,故相比于MessageCodec,MethodCodec多了对调用结果的处理。当方法调用成功时,使用encodeSuccessEnvelope将result编码为二进制数据,而当方法调用失败时,则使用encodeErrorEnvelope将error的code、message、detail编码为二进制数据
MethodCodec有两种实现:
1、继承SingleChildStatelessWidget,就是一个widget,通过create 传入一个Bloc对象
1、Bloc继承自BlocBase,BlocBase中创建了StreamController对象,为多订阅对象
其中onCounterEvent((event, emit)为初始化创建_eventController监听
2、Bloc中创建_eventController,为事件通知
3、BlocBase创建_stateController,为状态刷新通知
4、add方法是执行广播通知
5、处理完数据之后执行emit()方法,其中emit方法是stateController广播
1、 BlocBuilder继承自BlocBuilderBase,_BlocBuilderBaseState中build方法返回的是BlocListener
2、BlocListener继承BlocListenerBase,_BlocListenerBaseState中_subscribe()添加监听stateController广播通知
百度网盘flutter 见46-Flutter Channel
Flutter 提供三种Channel用作Flutter与iOS原生平台之间的数据传递
1.FlutterBasicMessageChannel: 用作频繁与原生交互
2.FlutterMethodChannel:用来调用方法,双向通讯
3.FlutterEventChannel:数据流通讯
三种Channel,都有以下成员变量
1.name: Channel 的唯一标识
在Flutter应用中,通常存在多个Platform Channel,使用name区分不同的Channel
2.messenger: 消息信使(BinaryMessenger)
负责Flutter与原生之间的相互通讯
[methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
}];
setMethodCallHandler方法,MethodCallHandler放在FlutterBinaryMessageHandler中
创建一个FlutterMethodChannel,通过 setMethodCallHandler来进行消息处理,最终会为FlutterMethodChannel绑定一个FlutterBinaryMessageHandler,并以FlutterMethodChannel的name作为key,保存在一个Map结构中
先创建 FlutterEngine-FlutterViewController-FlutterMethodChannel,
调用setMethodCallHandler方法时,会进入FlutterEngine的setMessageHandlerOnChannel:binaryMessageHandle:中,在进入PlatformMessageRouter中进行储存